/* THIS IS A GENERATED/BUNDLED FILE BY ESBUILD if you want to view the source, please visit the github repository of this plugin */ var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/main.ts var main_exports = {}; __export(main_exports, { DEFAULT_SETTINGS: () => DEFAULT_SETTINGS, checkActiveFile: () => checkActiveFile, default: () => BMOGPT15, defaultFrontMatter: () => defaultFrontMatter, updateFrontMatter: () => updateFrontMatter, updateProfile: () => updateProfile, updateSettingsFromFrontMatter: () => updateSettingsFromFrontMatter }); module.exports = __toCommonJS(main_exports); var import_obsidian27 = require("obsidian"); // src/view.ts var import_obsidian7 = require("obsidian"); // src/components/chat/Commands.ts var import_obsidian6 = require("obsidian"); // src/utils/ColorConverter.ts function colorToHex(colorValue) { if (colorValue.startsWith("hsl")) { const match = colorValue.match(/(\d+(\.\d+)?)%?/g); if (match === null || match.length < 3) { throw new Error("Invalid HSL value"); } const h = parseInt(match[0]) / 360; const s = parseInt(match[1]) / 100; const l = parseInt(match[2]) / 100; const q = l < 0.5 ? l * (1 + s) : l + s - l * s; const p = 2 * l - q; const r = hue2rgb(p, q, h + 1 / 3); const g2 = hue2rgb(p, q, h); const b = hue2rgb(p, q, h - 1 / 3); const toHex = function(c) { const hex2 = Math.round(c * 255).toString(16); return hex2.length === 1 ? "0" + hex2 : hex2; }; const hex = "#" + toHex(r) + toHex(g2) + toHex(b); return hex; } else if (colorValue.startsWith("rgb")) { const sep = colorValue.indexOf(",") > -1 ? "," : " "; const rgbArray = colorValue.substr(4).split(")")[0].split(sep); let r = (+rgbArray[0]).toString(16), g2 = (+rgbArray[1]).toString(16), b = (+rgbArray[2]).toString(16); if (r.length == 1) r = "0" + r; if (g2.length == 1) g2 = "0" + g2; if (b.length == 1) b = "0" + b; return "#" + r + g2 + b; } else { return colorValue; } } function hue2rgb(p, q, t) { if (t < 0) t += 1; if (t > 1) t -= 1; if (t < 1 / 6) return p + (q - p) * 6 * t; if (t < 1 / 2) return q; if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6; return p; } var isValidHexColor = (color) => { const hexColorRegex = /^[0-9A-Fa-f]{6}$/; return hexColorRegex.test(color); }; // src/components/FetchModelResponse.ts var import_obsidian4 = require("obsidian"); // src/components/chat/Buttons.ts var import_obsidian = require("obsidian"); // src/components/editor/ReferenceCurrentNote.ts var referenceCurrentNoteContent = ""; async function getActiveFileContent(plugin, settings) { const dotElement = document.querySelector(".dotIndicator"); referenceCurrentNoteContent = ""; if (settings.general.enableReferenceCurrentNote === true) { if (dotElement) { dotElement.style.backgroundColor = "#da2c2c"; referenceCurrentNoteContent = ""; } const activeFile = plugin.app.workspace.getActiveFile(); if ((activeFile == null ? void 0 : activeFile.extension) === "md") { if (dotElement) { dotElement.style.backgroundColor = "green"; } const content = await plugin.app.vault.read(activeFile); const clearYamlContent = content.replace(/---[\s\S]+?---/, "").trim(); referenceCurrentNoteContent = "\n\nAdditional Note:\n\n" + clearYamlContent + "\n\n"; } } return referenceCurrentNoteContent; } function getCurrentNoteContent() { return referenceCurrentNoteContent; } // src/components/chat/Buttons.ts function regenerateUserButton(plugin, settings) { const regenerateButton = document.createElement("button"); regenerateButton.textContent = "regenerate"; (0, import_obsidian.setIcon)(regenerateButton, "refresh-ccw"); regenerateButton.classList.add("regenerate-button"); regenerateButton.title = "regenerate"; let lastClickedElement = null; regenerateButton.addEventListener("click", async function(event) { event.stopPropagation(); lastClickedElement = event.target; while (lastClickedElement && !lastClickedElement.classList.contains("userMessage")) { lastClickedElement = lastClickedElement.parentElement; } let index2 = -1; if (lastClickedElement) { const userMessages = Array.from(document.querySelectorAll("#messageContainer .userMessage")); index2 = userMessages.indexOf(lastClickedElement) * 2; } if (index2 !== -1) { deleteMessage(plugin, index2 + 1); if (OPENAI_MODELS.includes(settings.general.model) || settings.APIConnections.openAI.openAIBaseModels.includes(settings.general.model)) { try { if (settings.APIConnections.openAI.enableStream) { await fetchOpenAIAPIResponseStream(plugin, settings, index2); } else { await fetchOpenAIAPIResponse(plugin, settings, index2); } } catch (error) { new import_obsidian.Notice("Error occurred while fetching completion: " + error.message); console.log(error.message); } } else if (settings.OllamaConnection.RESTAPIURL && settings.OllamaConnection.ollamaModels.includes(settings.general.model)) { if (settings.OllamaConnection.enableStream) { await fetchOllamaResponseStream(plugin, settings, index2); } else { await fetchOllamaResponse(plugin, settings, index2); } } else if (settings.RESTAPIURLConnection.RESTAPIURLModels.includes(settings.general.model)) { if (settings.RESTAPIURLConnection.enableStream) { await fetchRESTAPIURLResponseStream(plugin, settings, index2); } else { await fetchRESTAPIURLResponse(plugin, settings, index2); } } else if (settings.APIConnections.openRouter.openRouterModels.includes(settings.general.model)) { if (settings.APIConnections.openRouter.enableStream) { await fetchOpenRouterResponseStream(plugin, settings, index2); } else { await fetchOpenRouterResponse(plugin, settings, index2); } } else if (settings.APIConnections.mistral.mistralModels.includes(settings.general.model)) { try { if (settings.APIConnections.mistral.enableStream) { await fetchMistralResponseStream(plugin, settings, index2); } else { await fetchMistralResponse(plugin, settings, index2); } } catch (error) { console.error("Mistral Error:", error); } } else if (settings.APIConnections.googleGemini.geminiModels.includes(settings.general.model)) { try { if (settings.APIConnections.googleGemini.enableStream) { await fetchGoogleGeminiResponseStream(plugin, settings, index2); } else { await fetchGoogleGeminiResponse(plugin, settings, index2); } } catch (error) { console.error("Google Gemini Error:", error); } } else if (ANTHROPIC_MODELS.includes(settings.general.model)) { try { await fetchAnthropicResponse(plugin, settings, index2); } catch (error) { console.error("Anthropic Error:", error); } } } else { new import_obsidian.Notice("No models detected."); } }); return regenerateButton; } function displayUserEditButton(plugin, settings, userPre) { const editButton = document.createElement("button"); editButton.textContent = "edit"; (0, import_obsidian.setIcon)(editButton, "edit"); editButton.classList.add("edit-button"); editButton.title = "edit"; let lastClickedElement = null; editButton.addEventListener("click", function(event) { var _a2; const editContainer = document.createElement("div"); editContainer.classList.add("edit-container"); const textArea = document.createElement("textarea"); textArea.classList.add("edit-textarea"); textArea.value = (_a2 = userPre.textContent) != null ? _a2 : ""; editContainer.appendChild(textArea); const textareaEditButton = document.createElement("button"); textareaEditButton.textContent = "Edit"; textareaEditButton.classList.add("textarea-edit-button"); textareaEditButton.title = "edit"; const cancelButton = document.createElement("button"); cancelButton.textContent = "Cancel"; cancelButton.classList.add("textarea-cancel-button"); cancelButton.title = "cancel"; event.stopPropagation(); lastClickedElement = event.target; while (lastClickedElement && !lastClickedElement.classList.contains("userMessage")) { lastClickedElement = lastClickedElement.parentElement; } textareaEditButton.addEventListener("click", async function() { userPre.textContent = textArea.value.trim(); editContainer.replaceWith(userPre); if (lastClickedElement) { const userMessages = Array.from(document.querySelectorAll("#messageContainer .userMessage")); const index2 = userMessages.indexOf(lastClickedElement) * 2; if (index2 !== -1) { messageHistory[index2].content = textArea.value.trim(); deleteMessage(plugin, index2 + 1); const regex = /(!?)\[\[(.*?)\]\]/g; let matches; let inputModified = messageHistory[index2].content; const replacements = /* @__PURE__ */ new Map(); while ((matches = regex.exec(messageHistory[index2].content)) !== null) { const exclamation = matches[1]; const linktext = matches[2]; const [path, subpath] = linktext.split("#"); const file = plugin.app.metadataCache.getFirstLinkpathDest(path, ""); if (file && file instanceof import_obsidian.TFile) { try { const filePath = file.path; const fileExtension = filePath.split(".").pop(); if (fileExtension !== "md") { const isImageFile = /\.(jpg|jpeg|png|gif|webp|bmp|tiff|tif|svg)$/i.test(filePath); if (!plugin.settings.OllamaConnection.ollamaModels.includes(plugin.settings.general.model)) { replacements.set(matches[0], `${exclamation}[[${matches[2]}]]ERROR: File cannot be read.`); } else if (plugin.settings.OllamaConnection.ollamaModels.includes(plugin.settings.general.model)) { if (!isImageFile) { replacements.set(matches[0], `${exclamation}[[${matches[2]}]]ERROR: File cannot be read.`); } } continue; } const content = await plugin.app.vault.read(file); let contentToInsert = content; if (subpath) { const lines = content.split("\n"); let inSubpath = false; const subpathContent = []; let subpathLevel = 0; for (const line of lines) { if (line.startsWith("#")) { const match = line.match(/^#+/); const headingLevel = match ? match[0].length : 0; if (inSubpath) { if (headingLevel <= subpathLevel) { break; } } if (!inSubpath && line.toLowerCase().includes(subpath.toLowerCase())) { inSubpath = true; subpathLevel = headingLevel; } } if (inSubpath) { subpathContent.push(line); } } contentToInsert = subpathContent.join("\n"); } replacements.set(matches[0], `${exclamation}[[${matches[2]}]]${contentToInsert}`); } catch (err) { console.error(`Failed to read the content of "${path}": ${err}`); } } else { replacements.set(matches[0], `${exclamation}[[${matches[2]}]]File cannot be read.`); } } for (const [original, replacement] of replacements) { inputModified = inputModified.split(original).join(replacement); } inputModified = inputModified.replace(/(File cannot be read.<\/note-rendered>)+/g, "File cannot be read."); messageHistory[index2].content = inputModified; if (settings.OllamaConnection.RESTAPIURL && settings.OllamaConnection.ollamaModels.includes(settings.general.model)) { if (settings.OllamaConnection.enableStream) { await fetchOllamaResponseStream(plugin, settings, index2); } else { await fetchOllamaResponse(plugin, settings, index2); } } else if (settings.RESTAPIURLConnection.RESTAPIURLModels.includes(settings.general.model)) { if (settings.RESTAPIURLConnection.enableStream) { await fetchRESTAPIURLResponseStream(plugin, settings, index2); } else { await fetchRESTAPIURLResponse(plugin, settings, index2); } } else if (ANTHROPIC_MODELS.includes(settings.general.model)) { try { await fetchAnthropicResponse(plugin, settings, index2); } catch (error) { console.error("Anthropic Error:", error); } } else if (settings.APIConnections.googleGemini.geminiModels.includes(settings.general.model)) { try { if (settings.APIConnections.googleGemini.enableStream) { await fetchGoogleGeminiResponseStream(plugin, settings, index2); } else { await fetchGoogleGeminiResponse(plugin, settings, index2); } } catch (error) { console.error("Google GeminiError:", error); } } else if (settings.APIConnections.mistral.mistralModels.includes(settings.general.model)) { try { if (settings.APIConnections.mistral.enableStream) { await fetchMistralResponseStream(plugin, settings, index2); } else { await fetchMistralResponse(plugin, settings, index2); } } catch (error) { console.error("Mistral Error:", error); } } else if (OPENAI_MODELS.includes(settings.general.model) || settings.APIConnections.openAI.openAIBaseModels.includes(settings.general.model)) { try { if (settings.APIConnections.openAI.enableStream) { await fetchOpenAIAPIResponseStream(plugin, settings, index2); } else { await fetchOpenAIAPIResponse(plugin, settings, index2); } } catch (error) { new import_obsidian.Notice("Error occurred while fetching completion: " + error.message); console.log(error.message); } } else if (settings.APIConnections.openRouter.openRouterModels.includes(settings.general.model)) { if (settings.APIConnections.openRouter.enableStream) { await fetchOpenRouterResponseStream(plugin, settings, index2); } else { await fetchOpenRouterResponse(plugin, settings, index2); } } } else { new import_obsidian.Notice("No models detected."); } } }); cancelButton.addEventListener("click", function() { editContainer.replaceWith(userPre); }); editContainer.appendChild(textareaEditButton); editContainer.appendChild(cancelButton); if (userPre.parentNode !== null) { userPre.parentNode.replaceChild(editContainer, userPre); } }); return editButton; } function displayBotEditButton(plugin, message) { const editButton = document.createElement("button"); editButton.textContent = "edit"; (0, import_obsidian.setIcon)(editButton, "edit"); editButton.classList.add("edit-button"); editButton.title = "edit"; let lastClickedElement = null; editButton.addEventListener("click", function(event) { const editContainer = document.createElement("div"); editContainer.classList.add("edit-container"); const textArea = document.createElement("textarea"); textArea.classList.add("edit-textarea"); textArea.value = message; const textareaEditButton = document.createElement("button"); textareaEditButton.textContent = "Edit"; textareaEditButton.classList.add("textarea-edit-button"); textareaEditButton.title = "edit"; const cancelButton = document.createElement("button"); cancelButton.textContent = "Cancel"; cancelButton.classList.add("textarea-cancel-button"); cancelButton.title = "cancel"; editContainer.appendChild(textArea); event.stopPropagation(); lastClickedElement = event.target; while (lastClickedElement && !lastClickedElement.classList.contains("botMessage")) { lastClickedElement = lastClickedElement.parentElement; } let messageBlock = lastClickedElement == null ? void 0 : lastClickedElement.querySelector(".messageBlock"); if (messageBlock) { messageBlock.innerHTML = ""; messageBlock.appendChild(editContainer); } else { console.log("messageBlock not found."); } textareaEditButton.addEventListener("click", async function() { message = textArea.value; editContainer.remove(); messageBlock == null ? void 0 : messageBlock.remove(); messageBlock = document.createElement("div"); messageBlock.className = "messageBlock"; lastClickedElement == null ? void 0 : lastClickedElement.appendChild(messageBlock); await import_obsidian.MarkdownRenderer.render(plugin.app, message, messageBlock, "/", plugin); addParagraphBreaks(messageBlock); const copyCodeBlocks = messageBlock.querySelectorAll(".copy-code-button"); copyCodeBlocks.forEach((copyCodeBlock) => { copyCodeBlock.textContent = "Copy"; (0, import_obsidian.setIcon)(copyCodeBlock, "copy"); }); if (lastClickedElement) { const allMessages = Array.from(document.querySelectorAll("#messageContainer div.userMessage, #messageContainer div.botMessage")); const index2 = allMessages.indexOf(lastClickedElement); if (index2 !== -1) { const regex = /(!?)\[\[(.*?)\]\]/g; let matches; let inputModified = textArea.value; const replacements = /* @__PURE__ */ new Map(); while ((matches = regex.exec(textArea.value)) !== null) { const exclamation = matches[1]; const linktext = matches[2]; const [path, subpath] = linktext.split("#"); const file = plugin.app.metadataCache.getFirstLinkpathDest(path, ""); if (file && file instanceof import_obsidian.TFile) { try { const filePath = file.path; const fileExtension = filePath.split(".").pop(); if (fileExtension !== "md") { const isImageFile = /\.(jpg|jpeg|png|gif|webp|bmp|tiff|tif|svg)$/i.test(filePath); if (!plugin.settings.OllamaConnection.ollamaModels.includes(plugin.settings.general.model)) { replacements.set(matches[0], `${exclamation}[[${matches[2]}]]ERROR: File cannot be read.`); } else if (plugin.settings.OllamaConnection.ollamaModels.includes(plugin.settings.general.model)) { if (!isImageFile) { replacements.set(matches[0], `${exclamation}[[${matches[2]}]]ERROR: File cannot be read.`); } } continue; } const content = await plugin.app.vault.read(file); let contentToInsert = content; if (subpath) { const lines = content.split("\n"); let inSubpath = false; const subpathContent = []; let subpathLevel = 0; for (const line of lines) { if (line.startsWith("#")) { const match = line.match(/^#+/); const headingLevel = match ? match[0].length : 0; if (inSubpath) { if (headingLevel <= subpathLevel) { break; } } if (!inSubpath && line.toLowerCase().includes(subpath.toLowerCase())) { inSubpath = true; subpathLevel = headingLevel; } } if (inSubpath) { subpathContent.push(line); } } contentToInsert = subpathContent.join("\n"); } replacements.set(matches[0], `${exclamation}[[${matches[2]}]]${contentToInsert}`); } catch (err) { console.error(`Failed to read the content of "${path}": ${err}`); } } else { replacements.set(matches[0], `${exclamation}[[${matches[2]}]]File cannot be read.`); } } for (const [original, replacement] of replacements) { inputModified = inputModified.split(original).join(replacement); } inputModified = inputModified.replace(/(File cannot be read.<\/note-rendered>)+/g, "File cannot be read."); messageHistory[index2].content = inputModified; const jsonString = JSON.stringify(messageHistory, null, 4); try { await plugin.app.vault.adapter.write(fileNameMessageHistoryJson(plugin), jsonString); } catch (error) { console.error("Error writing to message history file:", error); } } else { new import_obsidian.Notice("No models detected."); } } }); cancelButton.addEventListener("click", async function() { editContainer.remove(); messageBlock == null ? void 0 : messageBlock.remove(); messageBlock = document.createElement("div"); messageBlock.className = "messageBlock"; lastClickedElement == null ? void 0 : lastClickedElement.appendChild(messageBlock); const regexRenderedBlock = /[\s\S]*?<\/block-rendered>/g; message = message.replace(regexRenderedBlock, "").trim(); const regexRenderedNote = /[\s\S]*?<\/note-rendered>/g; message = message.replace(regexRenderedNote, "").trim(); await import_obsidian.MarkdownRenderer.render(plugin.app, message, messageBlock, "/", plugin); addParagraphBreaks(messageBlock); const copyCodeBlocks = messageBlock.querySelectorAll(".copy-code-button"); copyCodeBlocks.forEach((copyCodeBlock) => { copyCodeBlock.textContent = "Copy"; (0, import_obsidian.setIcon)(copyCodeBlock, "copy"); }); }); editContainer.appendChild(textareaEditButton); editContainer.appendChild(cancelButton); }); return editButton; } function displayUserCopyButton(userPre) { const copyButton = document.createElement("button"); copyButton.textContent = "copy"; (0, import_obsidian.setIcon)(copyButton, "copy"); copyButton.classList.add("copy-button"); copyButton.title = "copy"; copyButton.addEventListener("click", function() { const messageText = userPre.textContent; if (messageText !== null) { copyMessageToClipboard(messageText); new import_obsidian.Notice("Copied user message."); } else { console.error("Message content is null. Cannot copy."); } }); return copyButton; } function displayBotCopyButton(settings, message) { const copyButton = document.createElement("button"); copyButton.textContent = "copy"; (0, import_obsidian.setIcon)(copyButton, "copy"); copyButton.classList.add("copy-button"); copyButton.title = "copy"; copyButton.addEventListener("click", function() { if (message !== null) { copyMessageToClipboard(message); new import_obsidian.Notice("Copied bot message."); } else { console.error("Message content is null. Cannot copy."); } }); return copyButton; } function copyMessageToClipboard(message) { navigator.clipboard.writeText(message).then(function() { }).catch(function(err) { console.error("Unable to copy message: ", err); }); } function displayAppendButton(plugin, settings, message) { const appendButton = document.createElement("button"); appendButton.textContent = "append"; (0, import_obsidian.setIcon)(appendButton, "plus-square"); appendButton.classList.add("append-button"); appendButton.title = "append"; const messageText = message; appendButton.addEventListener("click", async function(event) { var _a2, _b; if (((_a2 = checkActiveFile) == null ? void 0 : _a2.extension) === "md") { if (checkActiveFile !== lastCursorPositionFile) { getActiveFileContent(plugin, settings); const existingContent = await plugin.app.vault.read(checkActiveFile); const updatedContent = existingContent + "\n" + messageText; plugin.app.vault.modify(checkActiveFile, updatedContent); } else { (_b = activeEditor) == null ? void 0 : _b.replaceRange(messageText, lastCursorPosition); } event.stopPropagation(); new import_obsidian.Notice("Appended response."); } else { new import_obsidian.Notice("No active Markdown file detected."); } }); return appendButton; } function displayTrashButton(plugin) { const trashButton = document.createElement("button"); trashButton.textContent = "trash"; (0, import_obsidian.setIcon)(trashButton, "trash"); trashButton.classList.add("trash-button"); trashButton.title = "trash"; let lastClickedElement = null; trashButton.addEventListener("click", function(event) { event.stopPropagation(); lastClickedElement = event.target; while (lastClickedElement && !lastClickedElement.classList.contains("userMessage")) { lastClickedElement = lastClickedElement.parentElement; } if (lastClickedElement) { const userMessages = Array.from(document.querySelectorAll("#messageContainer .userMessage")); const index2 = userMessages.indexOf(lastClickedElement) * 2; if (index2 !== -1) { const modal = new import_obsidian.Modal(plugin.app); modal.contentEl.innerHTML = ` `; const confirmDeleteButton = modal.contentEl.querySelector("#confirmDelete"); confirmDeleteButton == null ? void 0 : confirmDeleteButton.addEventListener("click", async function() { deleteMessage(plugin, index2); new import_obsidian.Notice("Message deleted."); modal.close(); }); modal.open(); } } }); return trashButton; } async function deleteMessage(plugin, index2) { const messageContainer = document.querySelector("#messageContainer"); const divElements = messageContainer == null ? void 0 : messageContainer.querySelectorAll("div.botMessage, div.userMessage"); if (divElements && divElements.length > 0 && index2 >= 0 && index2 < divElements.length) { messageContainer == null ? void 0 : messageContainer.removeChild(divElements[index2]); if (index2 + 1 < divElements.length) { const nextMessage = divElements[index2 + 1]; if (nextMessage.classList.contains("botMessage")) { messageContainer == null ? void 0 : messageContainer.removeChild(nextMessage); } } } if (messageHistory[index2 + 1] && messageHistory[index2 + 1].role === "assistant") { messageHistory.splice(index2, 2); } else { messageHistory.splice(index2, 1); } const jsonString = JSON.stringify(messageHistory, null, 4); try { await plugin.app.vault.adapter.write(fileNameMessageHistoryJson(plugin), jsonString); } catch (error) { console.error("Error writing messageHistory.json", error); } } // src/components/chat/Message.ts var import_obsidian2 = require("obsidian"); async function addMessage(plugin, input, messageType, settings, index2) { const messageObj = { role: "", content: "", images: [] }; const referenceCurrentNoteContent2 = getCurrentNoteContent() || ""; const fullInput = referenceCurrentNoteContent2 + input; const imagesVaultPath = []; if (plugin.settings.OllamaConnection.ollamaModels.includes(plugin.settings.general.model)) { const imageMatch = fullInput.match(/!?\[\[(.*?)\]\]/g); const imageLink = imageMatch ? imageMatch.map((item) => item.startsWith("!") ? item.slice(3, -2) : item.slice(2, -2)).filter((link) => /\.(jpg|jpeg|png|gif|webp|bmp|tiff|tif|svg)$/i.test(link)) : []; if (imageLink.length > 0) { imageLink.forEach((link) => { const imageFile = this.app.metadataCache.getFirstLinkpathDest(link, ""); const image = imageFile ? this.app.vault.adapter.getFullPath(imageFile.path) : null; if (image) { imagesVaultPath.push(image); } }); } } if (messageType === "userMessage") { messageObj.role = "user"; messageObj.content = input; messageObj.images = imagesVaultPath; } else if (messageType === "botMessage") { messageObj.role = "assistant"; messageObj.content = input; const messageContainerElDivs = document.querySelectorAll("#messageContainer div.userMessage, #messageContainer div.botMessage"); const targetUserMessage = messageContainerElDivs[index2]; const targetBotMessage = targetUserMessage.nextElementSibling; const botMessageToolBarDiv = targetBotMessage == null ? void 0 : targetBotMessage.querySelector(".botMessageToolBar"); const buttonContainerDiv = document.createElement("div"); buttonContainerDiv.className = "button-container"; botMessageToolBarDiv == null ? void 0 : botMessageToolBarDiv.appendChild(buttonContainerDiv); const submitButton = document.querySelector(".submit-button"); submitButton.textContent = "send"; (0, import_obsidian2.setIcon)(submitButton, "arrow-up"); submitButton.title = "send"; if (!messageObj.content.includes("commandBotMessage") && !messageObj.content.includes("errorBotMessage")) { const editButton = displayBotEditButton(plugin, messageObj.content); const copyBotButton = displayBotCopyButton(settings, messageObj.content); const appendButton = displayAppendButton(plugin, settings, messageObj.content); buttonContainerDiv.appendChild(editButton); buttonContainerDiv.appendChild(copyBotButton); buttonContainerDiv.appendChild(appendButton); } } try { messageHistory.splice(index2 + 1, 0, messageObj); const jsonString = JSON.stringify(messageHistory, null, 4); await plugin.app.vault.adapter.write(fileNameMessageHistoryJson(plugin), jsonString); const messageContainerEl = document.getElementById("messageContainer"); if (messageContainerEl) { const lastBotMessage = messageContainerEl.querySelector(".botMessage:last-child"); if (lastBotMessage) { const getBlockLanguage = lastBotMessage.querySelectorAll('div[class^="block-language-"]'); const replacedLangaugeBlocks = /* @__PURE__ */ new Set(); getBlockLanguage.forEach(async (block) => { if (!block.querySelector(".rendered-markdown-output") && messageType === "botMessage") { const blockToMarkdown = (0, import_obsidian2.htmlToMarkdown)(block || ""); const markdownNode = document.createElement("div"); markdownNode.classList.add("rendered-markdown-output"); markdownNode.textContent = ` ${blockToMarkdown} `; let renderedMarkdownOutput = markdownNode.textContent; renderedMarkdownOutput = renderedMarkdownOutput.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (match, p1, p2) => { const filename = p2.split("/").pop().replace(".md", ""); return `[[${filename}]]`; }); const extractBlocks = (message) => { const regex = /```(\w+)\n([\s\S]*?)```(\s*([\s\S]*?<\/block-rendered>\s*)?)/g; let updatedMessage = message; for (const match of [...message.matchAll(regex)]) { const oldBlock = match[0]; const blockContent = match[2].trim(); if (replacedLangaugeBlocks.has(oldBlock)) { continue; } const newBlock = `\`\`\`${match[1]} ${blockContent} \`\`\`${renderedMarkdownOutput}`; updatedMessage = updatedMessage.replace(oldBlock, newBlock); replacedLangaugeBlocks.add(newBlock); break; } return updatedMessage; }; const updatedMessageContent = extractBlocks(messageObj.content); messageObj.content = updatedMessageContent; const updatedJsonString = JSON.stringify(messageHistory, null, 4); await plugin.app.vault.adapter.write(fileNameMessageHistoryJson(plugin), updatedJsonString); } }); const getNoteContent = lastBotMessage.querySelectorAll(".internal-embed.markdown-embed.inline-embed.is-loaded"); const replacedNoteBlocks = /* @__PURE__ */ new Set(); getNoteContent.forEach(async (link) => { if (!link.querySelector(".rendered-markdown-output")) { const blockToMarkdown = (0, import_obsidian2.htmlToMarkdown)(link || ""); const markdownNode = document.createElement("div"); markdownNode.classList.add("rendered-markdown-output"); markdownNode.textContent = ` ${blockToMarkdown} `; const renderedMarkdownOutput = markdownNode.textContent; const extractLinks = (message) => { const regex = /(!\[\[.*?\]\])(\s*([\s\S]*?<\/note-rendered>\s*)?)/g; let updatedMessage = message; for (const match of [...message.matchAll(regex)]) { const oldLink = match[0]; const noteLink = match[1]; if (replacedNoteBlocks.has(oldLink)) { continue; } const newLink = `${noteLink} ${renderedMarkdownOutput}`; updatedMessage = updatedMessage.replace(oldLink, newLink); replacedNoteBlocks.add(newLink); break; } return updatedMessage; }; const updatedMessageContent = extractLinks(messageObj.content); messageObj.content = updatedMessageContent; const updatedJsonString = JSON.stringify(messageHistory, null, 4); await plugin.app.vault.adapter.write(fileNameMessageHistoryJson(plugin), updatedJsonString); } }); } } } catch (error) { console.error("Error writing to message history file:", error); } } function addParagraphBreaks(messageBlock) { const paragraphs = messageBlock.querySelectorAll("p"); for (let i = 0; i < paragraphs.length; i++) { const p = paragraphs[i]; const nextSibling = p.nextElementSibling; if (nextSibling && nextSibling.nodeName === "P") { const br = document.createElement("br"); const parent = p.parentNode; if (parent) { parent.insertBefore(br, nextSibling); } } } } function updateUnresolvedInternalLinks(plugin, divBlock) { const internalLinks = divBlock.querySelectorAll("a"); internalLinks.forEach((link) => { let linkHref = link.getAttribute("href") || link.getAttribute("data-href"); if (linkHref) { if (linkHref.includes("#")) { linkHref = linkHref.split("#")[0]; } const linkExists = plugin.app.metadataCache.getFirstLinkpathDest(linkHref, ""); if (!linkExists) { link.style.color = "grey"; } } }); } // src/components/chat/BotMessage.ts var import_obsidian3 = require("obsidian"); function displayBotMessage(plugin, settings, messageHistory2, message) { const botMessageDiv = document.createElement("div"); botMessageDiv.className = "botMessage"; botMessageDiv.style.backgroundColor = colorToHex(settings.appearance.botMessageBackgroundColor || getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.botMessageBackgroundColor).trim()); botMessageDiv.style.color = settings.appearance.botMessageFontColor || DEFAULT_SETTINGS.appearance.botMessageFontColor; const botMessageToolBarDiv = document.createElement("div"); botMessageToolBarDiv.className = "botMessageToolBar"; const buttonContainerDiv = document.createElement("div"); buttonContainerDiv.className = "button-container"; const botNameSpan = document.createElement("span"); botNameSpan.textContent = settings.appearance.chatbotName || DEFAULT_SETTINGS.appearance.chatbotName; botNameSpan.className = "chatbotName"; botMessageToolBarDiv.appendChild(botNameSpan); botMessageToolBarDiv.appendChild(buttonContainerDiv); const messageBlockDiv = document.createElement("div"); messageBlockDiv.className = "messageBlock"; const regexRenderedBlock = /[\s\S]*?<\/block-rendered>/g; message = message.replace(regexRenderedBlock, "").trim(); const regexRenderedNote = /[\s\S]*?<\/note-rendered>/g; message = message.replace(regexRenderedNote, "").trim(); import_obsidian3.MarkdownRenderer.render(plugin.app, message, messageBlockDiv, "", plugin); if (!message.includes("commandBotMessage") && !message.includes("errorBotMessage")) { const editButton = displayBotEditButton(plugin, message); const copyBotButton = displayBotCopyButton(settings, message); const appendButton = displayAppendButton(plugin, settings, message); buttonContainerDiv.appendChild(editButton); buttonContainerDiv.appendChild(copyBotButton); buttonContainerDiv.appendChild(appendButton); addParagraphBreaks(messageBlockDiv); } const copyCodeBlocks = messageBlockDiv.querySelectorAll(".copy-code-button"); copyCodeBlocks.forEach((copyCodeBlock) => { copyCodeBlock.textContent = "Copy"; (0, import_obsidian3.setIcon)(copyCodeBlock, "copy"); }); botMessageDiv.appendChild(botMessageToolBarDiv); botMessageDiv.appendChild(messageBlockDiv); return botMessageDiv; } function displayLoadingBotMessage(settings) { const botMessageDiv = document.createElement("div"); botMessageDiv.className = "botMessage"; botMessageDiv.style.backgroundColor = colorToHex(settings.appearance.botMessageBackgroundColor || getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.botMessageBackgroundColor).trim()); botMessageDiv.style.color = settings.appearance.botMessageFontColor || DEFAULT_SETTINGS.appearance.botMessageFontColor; const botMessageToolBarDiv = document.createElement("div"); botMessageToolBarDiv.className = "botMessageToolBar"; const botNameSpan = document.createElement("span"); botNameSpan.textContent = settings.appearance.chatbotName || DEFAULT_SETTINGS.appearance.chatbotName; botNameSpan.className = "chatbotName"; const messageBlockDiv = document.createElement("div"); messageBlockDiv.className = "messageBlock"; const loadingEl = document.createElement("span"); loadingEl.setAttribute("id", "loading"); for (let i = 0; i < 3; i++) { const dotSpan = document.createElement("span"); dotSpan.textContent = "."; loadingEl.appendChild(dotSpan); } botMessageToolBarDiv.appendChild(botNameSpan); botMessageDiv.appendChild(botMessageToolBarDiv); botMessageDiv.appendChild(messageBlockDiv); botMessageDiv.appendChild(loadingEl); return botMessageDiv; } function displayCommandBotMessage(plugin, settings, messageHistory2, message) { const botMessageDiv = document.createElement("div"); botMessageDiv.className = "botMessage"; botMessageDiv.style.backgroundColor = colorToHex(settings.appearance.botMessageBackgroundColor || getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.botMessageBackgroundColor).trim()); const botMessageToolBarDiv = document.createElement("div"); botMessageToolBarDiv.className = "botMessageToolBar"; const botNameSpan = document.createElement("span"); botNameSpan.textContent = settings.appearance.chatbotName || DEFAULT_SETTINGS.appearance.chatbotName; botNameSpan.className = "chatbotName"; const messageBlockDiv = document.createElement("div"); messageBlockDiv.className = "messageBlock"; const displayCommandBotMessageDiv = document.createElement("div"); displayCommandBotMessageDiv.className = "commandBotMessage"; displayCommandBotMessageDiv.innerHTML = message; messageBlockDiv.appendChild(displayCommandBotMessageDiv); botMessageToolBarDiv.appendChild(botNameSpan); botMessageDiv.appendChild(botMessageToolBarDiv); botMessageDiv.appendChild(messageBlockDiv); const index2 = messageHistory2.length - 1; addMessage(plugin, messageBlockDiv.innerHTML, "botMessage", settings, index2); return botMessageDiv; } function displayErrorBotMessage(plugin, settings, messageHistory2, message) { const botMessageDiv = document.createElement("div"); botMessageDiv.className = "botMessage"; botMessageDiv.style.backgroundColor = colorToHex(settings.appearance.botMessageBackgroundColor || getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.botMessageBackgroundColor).trim()); const botMessageToolBarDiv = document.createElement("div"); botMessageToolBarDiv.className = "botMessageToolBar"; const botNameSpan = document.createElement("span"); botNameSpan.textContent = settings.appearance.chatbotName || DEFAULT_SETTINGS.appearance.chatbotName; botNameSpan.className = "chatbotName"; const messageBlockDiv = document.createElement("div"); messageBlockDiv.className = "messageBlock"; const displayErrorBotMessageDiv = document.createElement("div"); displayErrorBotMessageDiv.className = "errorBotMessage"; const BotP = document.createElement("p"); BotP.textContent = message; console.error(message); messageBlockDiv.appendChild(displayErrorBotMessageDiv); displayErrorBotMessageDiv.appendChild(BotP); botMessageToolBarDiv.appendChild(botNameSpan); botMessageDiv.appendChild(botMessageToolBarDiv); botMessageDiv.appendChild(messageBlockDiv); const index2 = messageHistory2.length - 1; addMessage(plugin, messageBlockDiv.innerHTML, "botMessage", this.settings, index2); return botMessageDiv; } // src/components/chat/Prompt.ts async function getPrompt(plugin, settings) { if (settings.prompts.prompt.trim() === "") { return ""; } const promptFilePath = settings.prompts.promptFolderPath + "/" + settings.prompts.prompt; try { const content = await plugin.app.vault.adapter.read(promptFilePath); const clearYamlContent = content.replace(/---[\s\S]+?---/, "").trim(); return "\n\n" + clearYamlContent + "\n\n"; } catch (error) { console.error(`Error reading file ${promptFilePath}:`, error); return null; } } // src/components/FetchModelResponse.ts var abortController = null; async function fetchOllamaResponse(plugin, settings, index2) { const ollamaRESTAPIURL = settings.OllamaConnection.RESTAPIURL; if (!ollamaRESTAPIURL) { return; } const prompt = await getPrompt(plugin, settings); const filteredMessageHistory = filterMessageHistory(messageHistory); const messageHistoryAtIndex = removeConsecutiveUserRoles(filteredMessageHistory); const messageContainerEl = document.querySelector("#messageContainer"); const messageContainerElDivs = document.querySelectorAll("#messageContainer div.userMessage, #messageContainer div.botMessage"); const botMessageDiv = displayLoadingBotMessage(settings); messageContainerEl == null ? void 0 : messageContainerEl.insertBefore(botMessageDiv, messageContainerElDivs[index2 + 1]); botMessageDiv.scrollIntoView({ behavior: "smooth", block: "start" }); await getActiveFileContent(plugin, settings); const referenceCurrentNoteContent2 = getCurrentNoteContent(); abortController = new AbortController(); const submitButton = document.querySelector(".submit-button"); (0, import_obsidian4.setIcon)(submitButton, "square"); submitButton.title = "stop"; submitButton.addEventListener("click", async () => { if (submitButton.title === "stop") { const controller = getAbortController(); if (controller) { controller.abort(); } } }); try { const response = await fetch(ollamaRESTAPIURL + "/api/chat", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ model: settings.general.model, messages: [ { role: "system", content: referenceCurrentNoteContent2 + settings.general.system_role + prompt + referenceCurrentNoteContent2 }, ...messageHistoryAtIndex ], stream: false, options: ollamaParametersOptions(settings) }), signal: abortController.signal }); const responseData = await response.json(); let message = responseData.message.content; if (messageContainerEl) { const targetUserMessage = messageContainerElDivs[index2]; const targetBotMessage = targetUserMessage.nextElementSibling; const messageBlock = targetBotMessage == null ? void 0 : targetBotMessage.querySelector(".messageBlock"); const loadingEl = targetBotMessage == null ? void 0 : targetBotMessage.querySelector("#loading"); if (messageBlock) { if (loadingEl) { targetBotMessage == null ? void 0 : targetBotMessage.removeChild(loadingEl); } await import_obsidian4.MarkdownRenderer.render(plugin.app, message || "", messageBlock, "/", plugin); addParagraphBreaks(messageBlock); updateUnresolvedInternalLinks(plugin, messageBlock); const copyCodeBlocks = messageBlock.querySelectorAll(".copy-code-button"); copyCodeBlocks.forEach((copyCodeBlock) => { copyCodeBlock.textContent = "Copy"; (0, import_obsidian4.setIcon)(copyCodeBlock, "copy"); }); targetBotMessage == null ? void 0 : targetBotMessage.appendChild(messageBlock); } targetBotMessage == null ? void 0 : targetBotMessage.scrollIntoView({ behavior: "smooth", block: "start" }); } const regexPatterns = [ /[\s\S]*?<\/block-rendered>/g, /[\s\S]*?<\/note-rendered>/g ]; regexPatterns.forEach((pattern) => { message = message.replace(pattern, "").trim(); }); addMessage(plugin, message.trim(), "botMessage", settings, index2); } catch (error) { if (error.name === "AbortError") { console.log("Request aborted"); (0, import_obsidian4.setIcon)(submitButton, "arrow-up"); submitButton.title = "send"; if (messageContainerEl) { const targetUserMessage = messageContainerElDivs[index2]; const targetBotMessage = targetUserMessage.nextElementSibling; const messageBlock = targetBotMessage == null ? void 0 : targetBotMessage.querySelector(".messageBlock"); const loadingEl = targetBotMessage == null ? void 0 : targetBotMessage.querySelector("#loading"); if (messageBlock && loadingEl) { targetBotMessage == null ? void 0 : targetBotMessage.removeChild(loadingEl); messageBlock.textContent = "SYSTEM: Response aborted."; addMessage(plugin, "SYSTEM: Response aborted.", "botMessage", settings, index2); } } } else { const targetUserMessage = messageContainerElDivs[index2]; const targetBotMessage = targetUserMessage.nextElementSibling; targetBotMessage == null ? void 0 : targetBotMessage.remove(); const messageContainer = document.querySelector("#messageContainer"); const botMessageDiv2 = displayErrorBotMessage(plugin, settings, messageHistory, error); messageContainer.appendChild(botMessageDiv2); } } finally { abortController = null; } } async function fetchOllamaResponseStream(plugin, settings, index2) { const ollamaRESTAPIURL = settings.OllamaConnection.RESTAPIURL; if (!ollamaRESTAPIURL) { return; } const prompt = await getPrompt(plugin, settings); const url = ollamaRESTAPIURL + "/api/chat"; abortController = new AbortController(); let message = ""; let isScroll = false; const filteredMessageHistory = filterMessageHistory(messageHistory); const messageHistoryAtIndex = removeConsecutiveUserRoles(filteredMessageHistory); const messageContainerEl = document.querySelector("#messageContainer"); const messageContainerElDivs = document.querySelectorAll("#messageContainer div.userMessage, #messageContainer div.botMessage"); const botMessageDiv = displayLoadingBotMessage(settings); messageContainerEl == null ? void 0 : messageContainerEl.insertBefore(botMessageDiv, messageContainerElDivs[index2 + 1]); botMessageDiv.scrollIntoView({ behavior: "smooth", block: "start" }); await getActiveFileContent(plugin, settings); const referenceCurrentNoteContent2 = getCurrentNoteContent(); const submitButton = document.querySelector(".submit-button"); (0, import_obsidian4.setIcon)(submitButton, "square"); submitButton.title = "stop"; submitButton.addEventListener("click", () => { if (submitButton.title === "stop") { const controller = getAbortController(); if (controller) { controller.abort(); } } }); try { const response = await fetch(url, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ model: settings.general.model, messages: [ { role: "system", content: settings.general.system_role + prompt + referenceCurrentNoteContent2 }, ...messageHistoryAtIndex ], stream: true, keep_alive: parseInt(settings.OllamaConnection.ollamaParameters.keep_alive), options: ollamaParametersOptions(settings) }), signal: abortController.signal }); if (!response.ok) { new import_obsidian4.Notice(`HTTP error! Status: ${response.status}`); throw new Error(`HTTP error! Status: ${response.status}`); } if (!response.body) { new import_obsidian4.Notice("Response body is null or undefined."); throw new Error("Response body is null or undefined."); } const reader = response.body.getReader(); const decoder = new TextDecoder(); let reading = true; while (reading) { const { done, value } = await reader.read(); if (done) { reading = false; break; } const chunk = decoder.decode(value, { stream: true }) || ""; const parts = chunk.split("\n"); for (const part of parts.filter(Boolean)) { let parsedChunk; try { parsedChunk = JSON.parse(part); if (parsedChunk.done !== true) { const content = parsedChunk.message.content; message += content; } } catch (err) { console.error("Error parsing JSON:", err); console.log("Part with error:", part); parsedChunk = { response: "{_e_}" }; } } const messageContainerEl2 = document.querySelector("#messageContainer"); if (messageContainerEl2) { const targetUserMessage = messageContainerElDivs[index2]; const targetBotMessage = targetUserMessage.nextElementSibling; const messageBlock = targetBotMessage == null ? void 0 : targetBotMessage.querySelector(".messageBlock"); const loadingEl = targetBotMessage == null ? void 0 : targetBotMessage.querySelector("#loading"); if (messageBlock) { if (loadingEl) { targetBotMessage == null ? void 0 : targetBotMessage.removeChild(loadingEl); } messageBlock.innerHTML = ""; const fragment = document.createDocumentFragment(); const tempContainer = document.createElement("div"); fragment.appendChild(tempContainer); await import_obsidian4.MarkdownRenderer.render(plugin.app, message, tempContainer, "/", plugin); while (tempContainer.firstChild) { messageBlock.appendChild(tempContainer.firstChild); } addParagraphBreaks(messageBlock); updateUnresolvedInternalLinks(plugin, messageBlock); const copyCodeBlocks = messageBlock.querySelectorAll(".copy-code-button"); copyCodeBlocks.forEach((copyCodeBlock) => { copyCodeBlock.textContent = "Copy"; (0, import_obsidian4.setIcon)(copyCodeBlock, "copy"); }); } messageContainerEl2.addEventListener("wheel", (event) => { if (event.deltaY < 0 || event.deltaY > 0) { isScroll = true; } }); if (!isScroll) { targetBotMessage == null ? void 0 : targetBotMessage.scrollIntoView({ behavior: "auto", block: "start" }); } } } const regexPatterns = [ /[\s\S]*?<\/block-rendered>/g, /[\s\S]*?<\/note-rendered>/g ]; regexPatterns.forEach((pattern) => { message = message.replace(pattern, "").trim(); }); addMessage(plugin, message.trim(), "botMessage", settings, index2); } catch (error) { if (error.name === "AbortError") { if (messageContainerEl) { const targetUserMessage = messageContainerElDivs[index2]; const targetBotMessage = targetUserMessage.nextElementSibling; const messageBlock = targetBotMessage == null ? void 0 : targetBotMessage.querySelector(".messageBlock"); const loadingEl = targetBotMessage == null ? void 0 : targetBotMessage.querySelector("#loading"); if (messageBlock && loadingEl) { targetBotMessage == null ? void 0 : targetBotMessage.removeChild(loadingEl); messageBlock.textContent = "SYSTEM: Response aborted."; } } } else { const targetUserMessage = messageContainerElDivs[index2]; const targetBotMessage = targetUserMessage.nextElementSibling; targetBotMessage == null ? void 0 : targetBotMessage.remove(); const messageContainer = document.querySelector("#messageContainer"); const botMessageDiv2 = displayErrorBotMessage(plugin, settings, messageHistory, error); messageContainer.appendChild(botMessageDiv2); } if (message.trim() === "") { addMessage(plugin, "SYSTEM: Response aborted.", "botMessage", settings, index2); } else { addMessage(plugin, message.trim(), "botMessage", settings, index2); } new import_obsidian4.Notice("Stream stopped."); console.error("Error fetching chat response from Ollama:", error); } finally { abortController = null; } submitButton.textContent = "send"; (0, import_obsidian4.setIcon)(submitButton, "arrow-up"); submitButton.title = "send"; } async function fetchRESTAPIURLResponse(plugin, settings, index2) { const prompt = await getPrompt(plugin, settings); const noImageMessageHistory = messageHistory.map(({ role, content }) => ({ role, content })); const filteredMessageHistory = filterMessageHistory(noImageMessageHistory); const messageHistoryAtIndex = removeConsecutiveUserRoles(filteredMessageHistory); const messageContainerEl = document.querySelector("#messageContainer"); const messageContainerElDivs = document.querySelectorAll("#messageContainer div.userMessage, #messageContainer div.botMessage"); const botMessageDiv = displayLoadingBotMessage(settings); messageContainerEl == null ? void 0 : messageContainerEl.insertBefore(botMessageDiv, messageContainerElDivs[index2 + 1]); botMessageDiv.scrollIntoView({ behavior: "smooth", block: "start" }); await getActiveFileContent(plugin, settings); const referenceCurrentNoteContent2 = getCurrentNoteContent(); try { const response = await (0, import_obsidian4.requestUrl)({ url: settings.RESTAPIURLConnection.RESTAPIURL + "/chat/completions", method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${settings.RESTAPIURLConnection.APIKey}` }, body: JSON.stringify({ model: settings.general.model, messages: [ { role: "system", content: settings.general.system_role + prompt + referenceCurrentNoteContent2 || "You are a helpful assistant." }, ...messageHistoryAtIndex ], max_tokens: parseInt(settings.general.max_tokens) || -1, temperature: parseInt(settings.general.temperature) }) }); let message = response.json.choices[0].message.content; const messageContainerEl2 = document.querySelector("#messageContainer"); if (messageContainerEl2) { const targetUserMessage = messageContainerElDivs[index2]; const targetBotMessage = targetUserMessage.nextElementSibling; const messageBlock = targetBotMessage == null ? void 0 : targetBotMessage.querySelector(".messageBlock"); const loadingEl = targetBotMessage == null ? void 0 : targetBotMessage.querySelector("#loading"); if (messageBlock) { if (loadingEl) { targetBotMessage == null ? void 0 : targetBotMessage.removeChild(loadingEl); } await import_obsidian4.MarkdownRenderer.render(plugin.app, message || "", messageBlock, "/", plugin); addParagraphBreaks(messageBlock); updateUnresolvedInternalLinks(plugin, messageBlock); const copyCodeBlocks = messageBlock.querySelectorAll(".copy-code-button"); copyCodeBlocks.forEach((copyCodeBlock) => { copyCodeBlock.textContent = "Copy"; (0, import_obsidian4.setIcon)(copyCodeBlock, "copy"); }); targetBotMessage == null ? void 0 : targetBotMessage.appendChild(messageBlock); } targetBotMessage == null ? void 0 : targetBotMessage.scrollIntoView({ behavior: "smooth", block: "start" }); } const regexPatterns = [ /[\s\S]*?<\/block-rendered>/g, /[\s\S]*?<\/note-rendered>/g ]; regexPatterns.forEach((pattern) => { message = message.replace(pattern, "").trim(); }); addMessage(plugin, message.trim(), "botMessage", settings, index2); return; } catch (error) { const targetUserMessage = messageContainerElDivs[index2]; const targetBotMessage = targetUserMessage.nextElementSibling; targetBotMessage == null ? void 0 : targetBotMessage.remove(); const messageContainer = document.querySelector("#messageContainer"); const botMessageDiv2 = displayErrorBotMessage(plugin, settings, messageHistory, error); messageContainer.appendChild(botMessageDiv2); } } async function fetchRESTAPIURLResponseStream(plugin, settings, index2) { const RESTAPIURL = settings.RESTAPIURLConnection.RESTAPIURL; if (!RESTAPIURL) { return; } const prompt = await getPrompt(plugin, settings); const url = RESTAPIURL + "/chat/completions"; abortController = new AbortController(); let message = ""; let isScroll = false; const noImageMessageHistory = messageHistory.map(({ role, content }) => ({ role, content })); const filteredMessageHistory = filterMessageHistory(noImageMessageHistory); const messageHistoryAtIndex = removeConsecutiveUserRoles(filteredMessageHistory); const messageContainerEl = document.querySelector("#messageContainer"); const messageContainerElDivs = document.querySelectorAll("#messageContainer div.userMessage, #messageContainer div.botMessage"); const botMessageDiv = displayLoadingBotMessage(settings); messageContainerEl == null ? void 0 : messageContainerEl.insertBefore(botMessageDiv, messageContainerElDivs[index2 + 1]); botMessageDiv.scrollIntoView({ behavior: "smooth", block: "start" }); await getActiveFileContent(plugin, settings); const referenceCurrentNoteContent2 = getCurrentNoteContent(); const submitButton = document.querySelector(".submit-button"); (0, import_obsidian4.setIcon)(submitButton, "square"); submitButton.title = "stop"; submitButton.addEventListener("click", () => { if (submitButton.title === "stop") { const controller = getAbortController(); if (controller) { controller.abort(); } } }); try { const response = await fetch(url, { method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${settings.RESTAPIURLConnection.APIKey}` }, body: JSON.stringify({ model: settings.general.model, messages: [ { role: "system", content: settings.general.system_role + prompt + referenceCurrentNoteContent2 || "You are a helpful assistant." }, ...messageHistoryAtIndex ], stream: true, temperature: parseInt(settings.general.temperature), max_tokens: parseInt(settings.general.max_tokens) || 4096 }), signal: abortController.signal }); if (!response.ok) { new import_obsidian4.Notice(`HTTP error! Status: ${response.status}`); throw new Error(`HTTP error! Status: ${response.status}`); } if (!response.body) { new import_obsidian4.Notice("Response body is null or undefined."); throw new Error("Response body is null or undefined."); } const reader = response.body.getReader(); const decoder = new TextDecoder(); let reading = true; while (reading) { const { done, value } = await reader.read(); if (done) { reading = false; break; } const chunk = decoder.decode(value, { stream: false }) || ""; const parts = chunk.split("\n"); for (const part of parts.filter(Boolean)) { if (part.includes("data: [DONE]")) { break; } let parsedChunk; try { parsedChunk = JSON.parse(part.replace(/^data: /, "")); if (parsedChunk.choices[0].finish_reason !== "stop") { const content = parsedChunk.choices[0].delta.content; message += content; } } catch (err) { console.error("Error parsing JSON:", err); console.log("Part with error:", part); parsedChunk = { response: "{_e_}" }; } } const messageContainerEl2 = document.querySelector("#messageContainer"); if (messageContainerEl2) { const targetUserMessage = messageContainerElDivs[index2]; const targetBotMessage = targetUserMessage.nextElementSibling; const messageBlock = targetBotMessage == null ? void 0 : targetBotMessage.querySelector(".messageBlock"); const loadingEl = targetBotMessage == null ? void 0 : targetBotMessage.querySelector("#loading"); if (messageBlock) { if (loadingEl) { targetBotMessage == null ? void 0 : targetBotMessage.removeChild(loadingEl); } messageBlock.innerHTML = ""; const fragment = document.createDocumentFragment(); const tempContainer = document.createElement("div"); fragment.appendChild(tempContainer); await import_obsidian4.MarkdownRenderer.render(plugin.app, message, tempContainer, "/", plugin); while (tempContainer.firstChild) { messageBlock.appendChild(tempContainer.firstChild); } addParagraphBreaks(messageBlock); updateUnresolvedInternalLinks(plugin, messageBlock); const copyCodeBlocks = messageBlock.querySelectorAll(".copy-code-button"); copyCodeBlocks.forEach((copyCodeBlock) => { copyCodeBlock.textContent = "Copy"; (0, import_obsidian4.setIcon)(copyCodeBlock, "copy"); }); } messageContainerEl2.addEventListener("wheel", (event) => { if (event.deltaY < 0 || event.deltaY > 0) { isScroll = true; } }); if (!isScroll) { targetBotMessage == null ? void 0 : targetBotMessage.scrollIntoView({ behavior: "auto", block: "start" }); } } } const regexPatterns = [ /[\s\S]*?<\/block-rendered>/g, /[\s\S]*?<\/note-rendered>/g ]; regexPatterns.forEach((pattern) => { message = message.replace(pattern, "").trim(); }); addMessage(plugin, message.trim(), "botMessage", settings, index2); } catch (error) { if (error.name === "AbortError") { if (messageContainerEl) { const targetUserMessage = messageContainerElDivs[index2]; const targetBotMessage = targetUserMessage.nextElementSibling; const messageBlock = targetBotMessage == null ? void 0 : targetBotMessage.querySelector(".messageBlock"); const loadingEl = targetBotMessage == null ? void 0 : targetBotMessage.querySelector("#loading"); if (messageBlock && loadingEl) { targetBotMessage == null ? void 0 : targetBotMessage.removeChild(loadingEl); messageBlock.textContent = "SYSTEM: Response aborted."; } } } else { const targetUserMessage = messageContainerElDivs[index2]; const targetBotMessage = targetUserMessage.nextElementSibling; targetBotMessage == null ? void 0 : targetBotMessage.remove(); const messageContainer = document.querySelector("#messageContainer"); const botMessageDiv2 = displayErrorBotMessage(plugin, settings, messageHistory, error); messageContainer.appendChild(botMessageDiv2); } if (message.trim() === "") { addMessage(plugin, "SYSTEM: Response aborted.", "botMessage", settings, index2); } else { addMessage(plugin, message.trim(), "botMessage", settings, index2); } new import_obsidian4.Notice("Stream stopped."); console.error("Error fetching chat response from Ollama:", error); } finally { abortController = null; } submitButton.textContent = "send"; (0, import_obsidian4.setIcon)(submitButton, "arrow-up"); submitButton.title = "send"; } async function fetchAnthropicResponse(plugin, settings, index2) { const prompt = await getPrompt(plugin, settings); const noImageMessageHistory = messageHistory.map(({ role, content }) => ({ role, content })); const filteredMessageHistory = filterMessageHistory(noImageMessageHistory); const messageHistoryAtIndex = removeConsecutiveUserRoles(filteredMessageHistory); const messageContainerEl = document.querySelector("#messageContainer"); const messageContainerElDivs = document.querySelectorAll("#messageContainer div.userMessage, #messageContainer div.botMessage"); const botMessageDiv = displayLoadingBotMessage(settings); messageContainerEl == null ? void 0 : messageContainerEl.insertBefore(botMessageDiv, messageContainerElDivs[index2 + 1]); botMessageDiv.scrollIntoView({ behavior: "smooth", block: "start" }); await getActiveFileContent(plugin, settings); const referenceCurrentNoteContent2 = getCurrentNoteContent(); abortController = new AbortController(); const submitButton = document.querySelector(".submit-button"); (0, import_obsidian4.setIcon)(submitButton, "square"); submitButton.title = "stop"; submitButton.addEventListener("click", async () => { if (submitButton.title === "stop") { const controller = getAbortController(); if (controller) { controller.abort(); } } }); try { const response = await (0, import_obsidian4.requestUrl)({ url: "https://api.anthropic.com/v1/messages", method: "POST", headers: { "anthropic-version": "2023-06-01", "content-type": "application/json", "x-api-key": settings.APIConnections.anthropic.APIKey }, body: JSON.stringify({ model: settings.general.model, system: settings.general.system_role + prompt + referenceCurrentNoteContent2, messages: [ ...messageHistoryAtIndex ], max_tokens: parseInt(settings.general.max_tokens) || 4096, temperature: parseInt(settings.general.temperature) }) }); let message = response.json.content[0].text; const messageContainerEl2 = document.querySelector("#messageContainer"); if (messageContainerEl2) { const targetUserMessage = messageContainerElDivs[index2]; const targetBotMessage = targetUserMessage.nextElementSibling; const messageBlock = targetBotMessage == null ? void 0 : targetBotMessage.querySelector(".messageBlock"); const loadingEl = targetBotMessage == null ? void 0 : targetBotMessage.querySelector("#loading"); if (messageBlock) { if (loadingEl) { targetBotMessage == null ? void 0 : targetBotMessage.removeChild(loadingEl); } await import_obsidian4.MarkdownRenderer.render(plugin.app, message || "", messageBlock, "/", plugin); addParagraphBreaks(messageBlock); updateUnresolvedInternalLinks(plugin, messageBlock); const copyCodeBlocks = messageBlock.querySelectorAll(".copy-code-button"); copyCodeBlocks.forEach((copyCodeBlock) => { copyCodeBlock.textContent = "Copy"; (0, import_obsidian4.setIcon)(copyCodeBlock, "copy"); }); targetBotMessage == null ? void 0 : targetBotMessage.appendChild(messageBlock); } targetBotMessage == null ? void 0 : targetBotMessage.scrollIntoView({ behavior: "smooth", block: "start" }); } const regexPatterns = [ /[\s\S]*?<\/block-rendered>/g, /[\s\S]*?<\/note-rendered>/g ]; regexPatterns.forEach((pattern) => { message = message.replace(pattern, "").trim(); }); addMessage(plugin, message.trim(), "botMessage", settings, index2); return; } catch (error) { const targetUserMessage = messageContainerElDivs[index2]; const targetBotMessage = targetUserMessage.nextElementSibling; targetBotMessage == null ? void 0 : targetBotMessage.remove(); const messageContainer = document.querySelector("#messageContainer"); const botMessageDiv2 = displayErrorBotMessage(plugin, settings, messageHistory, error); messageContainer.appendChild(botMessageDiv2); } } async function fetchGoogleGeminiResponse(plugin, settings, index2) { const prompt = await getPrompt(plugin, settings); const filteredMessageHistory = filterMessageHistory(messageHistory); const messageHistoryAtIndex = removeConsecutiveUserRoles(filteredMessageHistory); const messageContainerEl = document.querySelector("#messageContainer"); const messageContainerElDivs = document.querySelectorAll("#messageContainer div.userMessage, #messageContainer div.botMessage"); const botMessageDiv = displayLoadingBotMessage(settings); messageContainerEl == null ? void 0 : messageContainerEl.insertBefore(botMessageDiv, messageContainerElDivs[index2 + 1]); botMessageDiv.scrollIntoView({ behavior: "smooth", block: "start" }); await getActiveFileContent(plugin, settings); const referenceCurrentNoteContent2 = getCurrentNoteContent(); const convertMessageHistory = (messageHistory2) => { const modifiedMessageHistory = [...messageHistory2]; const convertedMessageHistory2 = modifiedMessageHistory.map(({ role, content }) => ({ role: role === "assistant" ? "model" : role, parts: [{ text: content }] })); const contents = [ ...convertedMessageHistory2 ]; return { contents }; }; const convertedMessageHistory = convertMessageHistory(messageHistoryAtIndex); abortController = new AbortController(); const submitButton = document.querySelector(".submit-button"); (0, import_obsidian4.setIcon)(submitButton, "square"); submitButton.title = "stop"; submitButton.addEventListener("click", async () => { if (submitButton.title === "stop") { const controller = getAbortController(); if (controller) { controller.abort(); } } }); try { const API_KEY = settings.APIConnections.googleGemini.APIKey; const MODEL = settings.general.model; const url = "https://generativelanguage.googleapis.com/v1beta/" + MODEL + ":generateContent?key=" + API_KEY; const response = await fetch(url, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ contents: [ { role: "user", parts: [{ text: `System prompt: ${plugin.settings.general.system_role} ${prompt} ${referenceCurrentNoteContent2} Respond understood if you got it.` }] }, { role: "model", parts: [{ text: "Understood." }] }, ...convertedMessageHistory.contents ], generationConfig: { stopSequences: "", temperature: parseInt(settings.general.temperature), maxOutputTokens: settings.general.max_tokens || 4096, topP: 0.8, topK: 10 } }), signal: abortController == null ? void 0 : abortController.signal }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const responseData = await response.json(); let message = responseData.candidates[0].content.parts[0].text; const messageContainerEl2 = document.querySelector("#messageContainer"); if (messageContainerEl2) { const targetUserMessage = messageContainerElDivs[index2]; const targetBotMessage = targetUserMessage.nextElementSibling; const messageBlock = targetBotMessage == null ? void 0 : targetBotMessage.querySelector(".messageBlock"); const loadingEl = targetBotMessage == null ? void 0 : targetBotMessage.querySelector("#loading"); if (messageBlock) { if (loadingEl) { targetBotMessage == null ? void 0 : targetBotMessage.removeChild(loadingEl); } await import_obsidian4.MarkdownRenderer.render(plugin.app, message || "", messageBlock, "/", plugin); addParagraphBreaks(messageBlock); updateUnresolvedInternalLinks(plugin, messageBlock); const copyCodeBlocks = messageBlock.querySelectorAll(".copy-code-button"); copyCodeBlocks.forEach((copyCodeBlock) => { copyCodeBlock.textContent = "Copy"; (0, import_obsidian4.setIcon)(copyCodeBlock, "copy"); }); targetBotMessage == null ? void 0 : targetBotMessage.appendChild(messageBlock); } targetBotMessage == null ? void 0 : targetBotMessage.scrollIntoView({ behavior: "smooth", block: "start" }); } const regexPatterns = [ /[\s\S]*?<\/block-rendered>/g, /[\s\S]*?<\/note-rendered>/g ]; regexPatterns.forEach((pattern) => { message = message.replace(pattern, "").trim(); }); addMessage(plugin, message.trim(), "botMessage", settings, index2); return; } catch (error) { if (error.name === "AbortError") { console.log("Request aborted"); (0, import_obsidian4.setIcon)(submitButton, "arrow-up"); submitButton.title = "send"; if (messageContainerEl) { const targetUserMessage = messageContainerElDivs[index2]; const targetBotMessage = targetUserMessage.nextElementSibling; const messageBlock = targetBotMessage == null ? void 0 : targetBotMessage.querySelector(".messageBlock"); const loadingEl = targetBotMessage == null ? void 0 : targetBotMessage.querySelector("#loading"); if (messageBlock && loadingEl) { targetBotMessage == null ? void 0 : targetBotMessage.removeChild(loadingEl); messageBlock.textContent = "SYSTEM: Response aborted."; addMessage(plugin, "SYSTEM: Response aborted.", "botMessage", settings, index2); } } } else { const targetUserMessage = messageContainerElDivs[index2]; const targetBotMessage = targetUserMessage.nextElementSibling; targetBotMessage == null ? void 0 : targetBotMessage.remove(); const messageContainer = document.querySelector("#messageContainer"); const botMessageDiv2 = displayErrorBotMessage(plugin, settings, messageHistory, error); messageContainer.appendChild(botMessageDiv2); } } finally { abortController = null; } } async function fetchGoogleGeminiResponseStream(plugin, settings, index2) { const prompt = await getPrompt(plugin, settings); abortController = new AbortController(); let message = ""; let isScroll = false; const filteredMessageHistory = filterMessageHistory(messageHistory); const messageHistoryAtIndex = removeConsecutiveUserRoles(filteredMessageHistory); const messageContainerEl = document.querySelector("#messageContainer"); const messageContainerElDivs = document.querySelectorAll("#messageContainer div.userMessage, #messageContainer div.botMessage"); const botMessageDiv = displayLoadingBotMessage(settings); messageContainerEl == null ? void 0 : messageContainerEl.insertBefore(botMessageDiv, messageContainerElDivs[index2 + 1]); botMessageDiv.scrollIntoView({ behavior: "smooth", block: "start" }); await getActiveFileContent(plugin, settings); const referenceCurrentNoteContent2 = getCurrentNoteContent(); const convertMessageHistory = (messageHistory2) => { const modifiedMessageHistory = [...messageHistory2]; const convertedMessageHistory2 = modifiedMessageHistory.map(({ role, content }) => ({ role: role === "assistant" ? "model" : role, parts: [{ text: content }] })); const contents = [ ...convertedMessageHistory2 ]; return { contents }; }; const convertedMessageHistory = convertMessageHistory(messageHistoryAtIndex); abortController = new AbortController(); const submitButton = document.querySelector(".submit-button"); (0, import_obsidian4.setIcon)(submitButton, "square"); submitButton.title = "stop"; submitButton.addEventListener("click", async () => { if (submitButton.title === "stop") { const controller = getAbortController(); if (controller) { controller.abort(); } } }); try { const API_KEY = settings.APIConnections.googleGemini.APIKey; const MODEL = settings.general.model; const url = "https://generativelanguage.googleapis.com/v1beta/" + MODEL + ":streamGenerateContent?alt=sse&key=" + API_KEY; const response = await fetch(url, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ contents: [ { role: "user", parts: [{ text: `System prompt: ${plugin.settings.general.system_role} ${prompt} ${referenceCurrentNoteContent2} Respond understood if you got it.` }] }, { role: "model", parts: [{ text: "Understood." }] }, ...convertedMessageHistory.contents ], generationConfig: { stopSequences: "", temperature: parseInt(settings.general.temperature), maxOutputTokens: settings.general.max_tokens || 4096, topP: 0.8, topK: 10 } }), signal: abortController == null ? void 0 : abortController.signal }); if (!response.ok) { new import_obsidian4.Notice(`HTTP error! Status: ${response.status}`); throw new Error(`HTTP error! Status: ${response.status}`); } if (!response.body) { new import_obsidian4.Notice("Response body is null or undefined."); throw new Error("Response body is null or undefined."); } const reader = response.body.getReader(); const decoder = new TextDecoder(); let reading = true; while (reading) { const { done, value } = await reader.read(); if (done) { reading = false; break; } const chunk = decoder.decode(value, { stream: true }) || ""; const parts = chunk.split("\n"); for (const part of parts.filter(Boolean)) { if (part.startsWith("data: ")) { const jsonData = part.slice(6); let parsedChunk; try { parsedChunk = JSON.parse(jsonData); if (parsedChunk.done !== true) { const content = parsedChunk.candidates[0].content.parts[0].text; message += content; } } catch (err) { console.error("Error parsing JSON:", err); console.log("Part with error:", jsonData); parsedChunk = { response: "{_e_}" }; } } } const messageContainerEl2 = document.querySelector("#messageContainer"); if (messageContainerEl2) { const targetUserMessage = messageContainerElDivs[index2]; const targetBotMessage = targetUserMessage.nextElementSibling; const messageBlock = targetBotMessage == null ? void 0 : targetBotMessage.querySelector(".messageBlock"); const loadingEl = targetBotMessage == null ? void 0 : targetBotMessage.querySelector("#loading"); if (messageBlock) { if (loadingEl) { targetBotMessage == null ? void 0 : targetBotMessage.removeChild(loadingEl); } messageBlock.innerHTML = ""; const fragment = document.createDocumentFragment(); const tempContainer = document.createElement("div"); fragment.appendChild(tempContainer); await import_obsidian4.MarkdownRenderer.render(plugin.app, message, tempContainer, "/", plugin); while (tempContainer.firstChild) { messageBlock.appendChild(tempContainer.firstChild); } addParagraphBreaks(messageBlock); updateUnresolvedInternalLinks(plugin, messageBlock); const copyCodeBlocks = messageBlock.querySelectorAll(".copy-code-button"); copyCodeBlocks.forEach((copyCodeBlock) => { copyCodeBlock.textContent = "Copy"; (0, import_obsidian4.setIcon)(copyCodeBlock, "copy"); }); } messageContainerEl2.addEventListener("wheel", (event) => { if (event.deltaY < 0 || event.deltaY > 0) { isScroll = true; } }); if (!isScroll) { targetBotMessage == null ? void 0 : targetBotMessage.scrollIntoView({ behavior: "auto", block: "start" }); } } } const regexPatterns = [ /[\s\S]*?<\/block-rendered>/g, /[\s\S]*?<\/note-rendered>/g ]; regexPatterns.forEach((pattern) => { message = message.replace(pattern, "").trim(); }); addMessage(plugin, message.trim(), "botMessage", settings, index2); } catch (error) { if (error.name === "AbortError") { if (messageContainerEl) { const targetUserMessage = messageContainerElDivs[index2]; const targetBotMessage = targetUserMessage.nextElementSibling; const messageBlock = targetBotMessage == null ? void 0 : targetBotMessage.querySelector(".messageBlock"); const loadingEl = targetBotMessage == null ? void 0 : targetBotMessage.querySelector("#loading"); if (messageBlock && loadingEl) { targetBotMessage == null ? void 0 : targetBotMessage.removeChild(loadingEl); messageBlock.textContent = "SYSTEM: Response aborted."; } } } else { const targetUserMessage = messageContainerElDivs[index2]; const targetBotMessage = targetUserMessage.nextElementSibling; targetBotMessage == null ? void 0 : targetBotMessage.remove(); const messageContainer = document.querySelector("#messageContainer"); const botMessageDiv2 = displayErrorBotMessage(plugin, settings, messageHistory, error); messageContainer.appendChild(botMessageDiv2); } if (message.trim() === "") { addMessage(plugin, "SYSTEM: Response aborted.", "botMessage", settings, index2); } else { addMessage(plugin, message.trim(), "botMessage", settings, index2); } new import_obsidian4.Notice("Stream stopped."); console.error("Error fetching chat response from Google Gemini:", error); } finally { abortController = null; } submitButton.textContent = "send"; (0, import_obsidian4.setIcon)(submitButton, "arrow-up"); submitButton.title = "send"; } async function fetchMistralResponse(plugin, settings, index2) { const prompt = await getPrompt(plugin, settings); const noImageMessageHistory = messageHistory.map(({ role, content }) => ({ role, content })); const filteredMessageHistory = filterMessageHistory(noImageMessageHistory); const messageHistoryAtIndex = removeConsecutiveUserRoles(filteredMessageHistory); const messageContainerEl = document.querySelector("#messageContainer"); const messageContainerElDivs = document.querySelectorAll("#messageContainer div.userMessage, #messageContainer div.botMessage"); const botMessageDiv = displayLoadingBotMessage(settings); messageContainerEl == null ? void 0 : messageContainerEl.insertBefore(botMessageDiv, messageContainerElDivs[index2 + 1]); botMessageDiv.scrollIntoView({ behavior: "smooth", block: "start" }); await getActiveFileContent(plugin, settings); const referenceCurrentNoteContent2 = getCurrentNoteContent(); abortController = new AbortController(); const submitButton = document.querySelector(".submit-button"); (0, import_obsidian4.setIcon)(submitButton, "square"); submitButton.title = "stop"; submitButton.addEventListener("click", async () => { if (submitButton.title === "stop") { const controller = getAbortController(); if (controller) { controller.abort(); } } }); try { const response = await fetch("https://api.mistral.ai/v1/chat/completions", { method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${settings.APIConnections.mistral.APIKey}` }, body: JSON.stringify({ model: settings.general.model, messages: [ { role: "system", content: settings.general.system_role + prompt + referenceCurrentNoteContent2 }, ...messageHistoryAtIndex ], max_tokens: parseInt(settings.general.max_tokens) || 4096, temperature: parseInt(settings.general.temperature) }), signal: abortController == null ? void 0 : abortController.signal }); const data = await response.json(); let message = data.choices[0].message.content; const messageContainerEl2 = document.querySelector("#messageContainer"); if (messageContainerEl2) { const targetUserMessage = messageContainerElDivs[index2]; const targetBotMessage = targetUserMessage.nextElementSibling; const messageBlock = targetBotMessage == null ? void 0 : targetBotMessage.querySelector(".messageBlock"); const loadingEl = targetBotMessage == null ? void 0 : targetBotMessage.querySelector("#loading"); if (messageBlock) { if (loadingEl) { targetBotMessage == null ? void 0 : targetBotMessage.removeChild(loadingEl); } await import_obsidian4.MarkdownRenderer.render(plugin.app, message || "", messageBlock, "/", plugin); addParagraphBreaks(messageBlock); updateUnresolvedInternalLinks(plugin, messageBlock); const copyCodeBlocks = messageBlock.querySelectorAll(".copy-code-button"); copyCodeBlocks.forEach((copyCodeBlock) => { copyCodeBlock.textContent = "Copy"; (0, import_obsidian4.setIcon)(copyCodeBlock, "copy"); }); targetBotMessage == null ? void 0 : targetBotMessage.appendChild(messageBlock); } targetBotMessage == null ? void 0 : targetBotMessage.scrollIntoView({ behavior: "smooth", block: "start" }); } const regexPatterns = [ /[\s\S]*?<\/block-rendered>/g, /[\s\S]*?<\/note-rendered>/g ]; regexPatterns.forEach((pattern) => { message = message.replace(pattern, "").trim(); }); addMessage(plugin, message.trim(), "botMessage", settings, index2); return; } catch (error) { if (error.name === "AbortError") { console.log("Request aborted"); (0, import_obsidian4.setIcon)(submitButton, "arrow-up"); submitButton.title = "send"; if (messageContainerEl) { const targetUserMessage = messageContainerElDivs[index2]; const targetBotMessage = targetUserMessage.nextElementSibling; const messageBlock = targetBotMessage == null ? void 0 : targetBotMessage.querySelector(".messageBlock"); const loadingEl = targetBotMessage == null ? void 0 : targetBotMessage.querySelector("#loading"); if (messageBlock && loadingEl) { targetBotMessage == null ? void 0 : targetBotMessage.removeChild(loadingEl); messageBlock.textContent = "SYSTEM: Response aborted."; addMessage(plugin, "SYSTEM: Response aborted.", "botMessage", settings, index2); } } } else { const targetUserMessage = messageContainerElDivs[index2]; const targetBotMessage = targetUserMessage.nextElementSibling; targetBotMessage == null ? void 0 : targetBotMessage.remove(); const messageContainer = document.querySelector("#messageContainer"); const botMessageDiv2 = displayErrorBotMessage(plugin, settings, messageHistory, error); messageContainer.appendChild(botMessageDiv2); } } finally { abortController = null; } } async function fetchMistralResponseStream(plugin, settings, index2) { abortController = new AbortController(); const prompt = await getPrompt(plugin, settings); let message = ""; let isScroll = false; const noImageMessageHistory = messageHistory.map(({ role, content }) => ({ role, content })); const filteredMessageHistory = filterMessageHistory(noImageMessageHistory); const messageHistoryAtIndex = removeConsecutiveUserRoles(filteredMessageHistory); const messageContainerEl = document.querySelector("#messageContainer"); const messageContainerElDivs = document.querySelectorAll("#messageContainer div.userMessage, #messageContainer div.botMessage"); const botMessageDiv = displayLoadingBotMessage(settings); messageContainerEl == null ? void 0 : messageContainerEl.insertBefore(botMessageDiv, messageContainerElDivs[index2 + 1]); botMessageDiv.scrollIntoView({ behavior: "smooth", block: "start" }); await getActiveFileContent(plugin, settings); const referenceCurrentNoteContent2 = getCurrentNoteContent(); abortController = new AbortController(); const submitButton = document.querySelector(".submit-button"); (0, import_obsidian4.setIcon)(submitButton, "square"); submitButton.title = "stop"; submitButton.addEventListener("click", async () => { if (submitButton.title === "stop") { const controller = getAbortController(); if (controller) { controller.abort(); } } }); try { const response = await fetch("https://api.mistral.ai/v1/chat/completions", { method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${settings.APIConnections.mistral.APIKey}` }, body: JSON.stringify({ model: settings.general.model, messages: [ { role: "system", content: settings.general.system_role + prompt + referenceCurrentNoteContent2 }, ...messageHistoryAtIndex ], stream: true, temperature: parseInt(settings.general.temperature), max_tokens: parseInt(settings.general.max_tokens) || 4096 }), signal: abortController.signal }); (0, import_obsidian4.setIcon)(submitButton, "square"); submitButton.title = "stop"; if (!response.ok) { new import_obsidian4.Notice(`HTTP error! Status: ${response.status}`); throw new Error(`HTTP error! Status: ${response.status}`); } if (!response.body) { new import_obsidian4.Notice("Response body is null or undefined."); throw new Error("Response body is null or undefined."); } const reader = response.body.getReader(); const decoder = new TextDecoder(); let reading = true; while (reading) { const { done, value } = await reader.read(); if (done) { reading = false; break; } const chunk = decoder.decode(value, { stream: false }) || ""; const parts = chunk.split("\n"); for (const part of parts.filter(Boolean)) { if (part.includes("data: [DONE]")) { break; } let parsedChunk; try { parsedChunk = JSON.parse(part.replace(/^data: /, "")); if (parsedChunk.choices[0].finish_reason !== "stop") { const content = parsedChunk.choices[0].delta.content; message += content; } } catch (err) { console.error("Error parsing JSON:", err); console.log("Part with error:", part); parsedChunk = { response: "{_e_}" }; } } const messageContainerEl2 = document.querySelector("#messageContainer"); if (messageContainerEl2) { const targetUserMessage = messageContainerElDivs[index2]; const targetBotMessage = targetUserMessage.nextElementSibling; const messageBlock = targetBotMessage == null ? void 0 : targetBotMessage.querySelector(".messageBlock"); const loadingEl = targetBotMessage == null ? void 0 : targetBotMessage.querySelector("#loading"); if (messageBlock) { if (loadingEl) { targetBotMessage == null ? void 0 : targetBotMessage.removeChild(loadingEl); } messageBlock.innerHTML = ""; const fragment = document.createDocumentFragment(); const tempContainer = document.createElement("div"); fragment.appendChild(tempContainer); await import_obsidian4.MarkdownRenderer.render(plugin.app, message, tempContainer, "/", plugin); while (tempContainer.firstChild) { messageBlock.appendChild(tempContainer.firstChild); } addParagraphBreaks(messageBlock); updateUnresolvedInternalLinks(plugin, messageBlock); const copyCodeBlocks = messageBlock.querySelectorAll(".copy-code-button"); copyCodeBlocks.forEach((copyCodeBlock) => { copyCodeBlock.textContent = "Copy"; (0, import_obsidian4.setIcon)(copyCodeBlock, "copy"); }); } messageContainerEl2.addEventListener("wheel", (event) => { if (event.deltaY < 0 || event.deltaY > 0) { isScroll = true; } }); if (!isScroll) { targetBotMessage == null ? void 0 : targetBotMessage.scrollIntoView({ behavior: "auto", block: "start" }); } } } const regexPatterns = [ /[\s\S]*?<\/block-rendered>/g, /[\s\S]*?<\/note-rendered>/g ]; regexPatterns.forEach((pattern) => { message = message.replace(pattern, "").trim(); }); addMessage(plugin, message.trim(), "botMessage", settings, index2); } catch (error) { if (error.name === "AbortError") { if (messageContainerEl) { const targetUserMessage = messageContainerElDivs[index2]; const targetBotMessage = targetUserMessage.nextElementSibling; const messageBlock = targetBotMessage == null ? void 0 : targetBotMessage.querySelector(".messageBlock"); const loadingEl = targetBotMessage == null ? void 0 : targetBotMessage.querySelector("#loading"); if (messageBlock && loadingEl) { targetBotMessage == null ? void 0 : targetBotMessage.removeChild(loadingEl); messageBlock.textContent = "SYSTEM: Response aborted."; } } } else { const targetUserMessage = messageContainerElDivs[index2]; const targetBotMessage = targetUserMessage.nextElementSibling; targetBotMessage == null ? void 0 : targetBotMessage.remove(); const messageContainer = document.querySelector("#messageContainer"); const botMessageDiv2 = displayErrorBotMessage(plugin, settings, messageHistory, error); messageContainer.appendChild(botMessageDiv2); } if (message.trim() === "") { addMessage(plugin, "SYSTEM: Response aborted.", "botMessage", settings, index2); } else { addMessage(plugin, message.trim(), "botMessage", settings, index2); } new import_obsidian4.Notice("Stream stopped."); console.error("Error fetching chat response from Mistral:", error); } finally { abortController = null; } submitButton.textContent = "send"; (0, import_obsidian4.setIcon)(submitButton, "arrow-up"); submitButton.title = "send"; } async function fetchOpenAIAPIResponse(plugin, settings, index2) { abortController = new AbortController(); const prompt = await getPrompt(plugin, settings); const filteredMessageHistory = filterMessageHistory(messageHistory); const messageHistoryAtIndex = removeConsecutiveUserRoles(filteredMessageHistory); const messageContainerEl = document.querySelector("#messageContainer"); const messageContainerElDivs = document.querySelectorAll("#messageContainer div.userMessage, #messageContainer div.botMessage"); const botMessageDiv = displayLoadingBotMessage(settings); messageContainerEl == null ? void 0 : messageContainerEl.insertBefore(botMessageDiv, messageContainerElDivs[index2 + 1]); botMessageDiv.scrollIntoView({ behavior: "smooth", block: "start" }); await getActiveFileContent(plugin, settings); const referenceCurrentNoteContent2 = getCurrentNoteContent(); const submitButton = document.querySelector(".submit-button"); (0, import_obsidian4.setIcon)(submitButton, "square"); submitButton.title = "stop"; submitButton.addEventListener("click", async () => { if (submitButton.title === "stop") { const controller = getAbortController(); if (controller) { controller.abort(); } } }); try { const response = await fetch(`${plugin.settings.APIConnections.openAI.openAIBaseUrl}/chat/completions`, { method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${plugin.settings.APIConnections.openAI.APIKey}` }, body: JSON.stringify({ model: settings.general.model, max_tokens: parseInt(settings.general.max_tokens), stream: false, messages: [ { role: "system", content: settings.general.system_role + prompt + referenceCurrentNoteContent2 }, ...messageHistoryAtIndex ] }), signal: abortController.signal }); const data = await response.json(); let message = data.choices[0].message.content || ""; if (messageContainerEl) { const targetUserMessage = messageContainerElDivs[index2]; const targetBotMessage = targetUserMessage.nextElementSibling; const messageBlock = targetBotMessage == null ? void 0 : targetBotMessage.querySelector(".messageBlock"); const loadingEl = targetBotMessage == null ? void 0 : targetBotMessage.querySelector("#loading"); if (messageBlock) { if (loadingEl) { targetBotMessage == null ? void 0 : targetBotMessage.removeChild(loadingEl); } await import_obsidian4.MarkdownRenderer.render(plugin.app, message || "", messageBlock, "/", plugin); addParagraphBreaks(messageBlock); updateUnresolvedInternalLinks(plugin, messageBlock); const copyCodeBlocks = messageBlock.querySelectorAll(".copy-code-button"); copyCodeBlocks.forEach((copyCodeBlock) => { copyCodeBlock.textContent = "Copy"; (0, import_obsidian4.setIcon)(copyCodeBlock, "copy"); }); targetBotMessage == null ? void 0 : targetBotMessage.appendChild(messageBlock); } targetBotMessage == null ? void 0 : targetBotMessage.scrollIntoView({ behavior: "smooth", block: "start" }); } if (message != null) { const regexPatterns = [ /[\s\S]*?<\/block-rendered>/g, /[\s\S]*?<\/note-rendered>/g, /[\s\S]*?<\/note-rendered>/g ]; regexPatterns.forEach((pattern) => { message = message.replace(pattern, "").trim(); }); addMessage(plugin, message.trim(), "botMessage", settings, index2); } } catch (error) { if (error.name === "AbortError") { console.log("Request aborted"); (0, import_obsidian4.setIcon)(submitButton, "arrow-up"); submitButton.title = "send"; if (messageContainerEl) { const targetUserMessage = messageContainerElDivs[index2]; const targetBotMessage = targetUserMessage.nextElementSibling; const messageBlock = targetBotMessage == null ? void 0 : targetBotMessage.querySelector(".messageBlock"); const loadingEl = targetBotMessage == null ? void 0 : targetBotMessage.querySelector("#loading"); if (messageBlock && loadingEl) { targetBotMessage == null ? void 0 : targetBotMessage.removeChild(loadingEl); messageBlock.textContent = "SYSTEM: Response aborted."; addMessage(plugin, "SYSTEM: Response aborted.", "botMessage", settings, index2); } } } else { const targetUserMessage = messageContainerElDivs[index2]; const targetBotMessage = targetUserMessage.nextElementSibling; targetBotMessage == null ? void 0 : targetBotMessage.remove(); const messageContainer = document.querySelector("#messageContainer"); const botMessageDiv2 = displayErrorBotMessage(plugin, settings, messageHistory, error); messageContainer.appendChild(botMessageDiv2); } } finally { abortController = null; } } async function fetchOpenAIAPIResponseStream(plugin, settings, index2) { abortController = new AbortController(); const prompt = await getPrompt(plugin, settings); let message = ""; let isScroll = false; const filteredMessageHistory = filterMessageHistory(messageHistory); const messageHistoryAtIndex = removeConsecutiveUserRoles(filteredMessageHistory); const messageContainerEl = document.querySelector("#messageContainer"); const messageContainerElDivs = document.querySelectorAll("#messageContainer div.userMessage, #messageContainer div.botMessage"); const botMessageDiv = displayLoadingBotMessage(settings); messageContainerEl == null ? void 0 : messageContainerEl.insertBefore(botMessageDiv, messageContainerElDivs[index2 + 1]); botMessageDiv.scrollIntoView({ behavior: "smooth", block: "start" }); const targetUserMessage = messageContainerElDivs[index2]; const targetBotMessage = targetUserMessage.nextElementSibling; await getActiveFileContent(plugin, settings); const referenceCurrentNoteContent2 = getCurrentNoteContent(); const submitButton = document.querySelector(".submit-button"); (0, import_obsidian4.setIcon)(submitButton, "square"); submitButton.title = "stop"; submitButton.addEventListener("click", () => { if (submitButton.title === "stop") { const controller = getAbortController(); if (controller) { controller.abort(); } } }); try { const response = await fetch(`${plugin.settings.APIConnections.openAI.openAIBaseUrl}/chat/completions`, { method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${plugin.settings.APIConnections.openAI.APIKey}` }, body: JSON.stringify({ model: settings.general.model, max_tokens: parseInt(settings.general.max_tokens), stream: true, messages: [ { role: "system", content: settings.general.system_role + prompt + referenceCurrentNoteContent2 }, ...messageHistoryAtIndex ] }), signal: abortController.signal }); if (!response.ok) { new import_obsidian4.Notice(`HTTP error! Status: ${response.status}`); throw new Error(`HTTP error! Status: ${response.status}`); } if (!response.body) { new import_obsidian4.Notice("Response body is null or undefined."); throw new Error("Response body is null or undefined."); } const reader = response.body.getReader(); const decoder = new TextDecoder(); let reading = true; while (reading) { const { done, value } = await reader.read(); if (done) { reading = false; break; } const chunk = decoder.decode(value, { stream: true }) || ""; const parts = chunk.split("\n"); for (const part of parts) { if (part.includes("data: [DONE]")) { reading = false; break; } try { const trimmedPart = part.replace(/^data: /, "").trim(); if (trimmedPart) { const data = JSON.parse(trimmedPart); if (data.choices && data.choices[0].delta && data.choices[0].delta.content) { const content = data.choices[0].delta.content; message += content; } } } catch (err) { console.error("Error parsing JSON:", err); console.log("Part with error:", part); } } if (messageContainerEl) { const messageBlock = targetBotMessage == null ? void 0 : targetBotMessage.querySelector(".messageBlock"); const loadingEl = targetBotMessage == null ? void 0 : targetBotMessage.querySelector("#loading"); if (messageBlock) { if (loadingEl) { targetBotMessage == null ? void 0 : targetBotMessage.removeChild(loadingEl); } messageBlock.innerHTML = ""; const fragment = document.createDocumentFragment(); const tempContainer = document.createElement("div"); fragment.appendChild(tempContainer); await import_obsidian4.MarkdownRenderer.render(plugin.app, message, tempContainer, "/", plugin); while (tempContainer.firstChild) { messageBlock.appendChild(tempContainer.firstChild); } addParagraphBreaks(messageBlock); updateUnresolvedInternalLinks(plugin, messageBlock); const copyCodeBlocks = messageBlock.querySelectorAll(".copy-code-button"); copyCodeBlocks.forEach((copyCodeBlock) => { copyCodeBlock.textContent = "Copy"; (0, import_obsidian4.setIcon)(copyCodeBlock, "copy"); }); } messageContainerEl.addEventListener("wheel", (event) => { if (event.deltaY < 0 || event.deltaY > 0) { isScroll = true; } }); if (!isScroll) { targetBotMessage == null ? void 0 : targetBotMessage.scrollIntoView({ behavior: "auto", block: "start" }); } } if (abortController.signal.aborted) { new import_obsidian4.Notice("Stream stopped."); break; } } const regexPatterns = [ /[\s\S]*?<\/block-rendered>/g, /[\s\S]*?<\/note-rendered>/g ]; regexPatterns.forEach((pattern) => { message = message.replace(pattern, "").trim(); }); addMessage(plugin, message.trim(), "botMessage", settings, index2); } catch (error) { if (error.name === "AbortError") { if (messageContainerEl) { const targetUserMessage2 = messageContainerElDivs[index2]; const targetBotMessage2 = targetUserMessage2.nextElementSibling; const messageBlock = targetBotMessage2 == null ? void 0 : targetBotMessage2.querySelector(".messageBlock"); const loadingEl = targetBotMessage2 == null ? void 0 : targetBotMessage2.querySelector("#loading"); if (messageBlock && loadingEl) { targetBotMessage2 == null ? void 0 : targetBotMessage2.removeChild(loadingEl); messageBlock.textContent = "SYSTEM: Response aborted."; } } } else { const targetUserMessage2 = messageContainerElDivs[index2]; const targetBotMessage2 = targetUserMessage2.nextElementSibling; targetBotMessage2 == null ? void 0 : targetBotMessage2.remove(); const messageContainer = document.querySelector("#messageContainer"); const botMessageDiv2 = displayErrorBotMessage(plugin, settings, messageHistory, error); messageContainer.appendChild(botMessageDiv2); } if (message.trim() === "") { addMessage(plugin, "SYSTEM: Response aborted.", "botMessage", settings, index2); } else { addMessage(plugin, message.trim(), "botMessage", settings, index2); } new import_obsidian4.Notice("Stream stopped."); console.error("Error fetching chat response from OpenAI-Based Models:", error); } finally { abortController = null; } submitButton.textContent = "send"; (0, import_obsidian4.setIcon)(submitButton, "arrow-up"); submitButton.title = "send"; } async function fetchOpenRouterResponse(plugin, settings, index2) { abortController = new AbortController(); const prompt = await getPrompt(plugin, settings); const filteredMessageHistory = filterMessageHistory(messageHistory); const messageHistoryAtIndex = removeConsecutiveUserRoles(filteredMessageHistory); const messageContainerEl = document.querySelector("#messageContainer"); const messageContainerElDivs = document.querySelectorAll("#messageContainer div.userMessage, #messageContainer div.botMessage"); const botMessageDiv = displayLoadingBotMessage(settings); messageContainerEl == null ? void 0 : messageContainerEl.insertBefore(botMessageDiv, messageContainerElDivs[index2 + 1]); botMessageDiv.scrollIntoView({ behavior: "smooth", block: "start" }); await getActiveFileContent(plugin, settings); const referenceCurrentNoteContent2 = getCurrentNoteContent(); const submitButton = document.querySelector(".submit-button"); (0, import_obsidian4.setIcon)(submitButton, "square"); submitButton.title = "stop"; submitButton.addEventListener("click", async () => { if (submitButton.title === "stop") { const controller = getAbortController(); if (controller) { controller.abort(); } } }); try { const response = await fetch("https://openrouter.ai/api/v1/chat/completions", { method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${settings.APIConnections.openRouter.APIKey}` }, body: JSON.stringify({ model: settings.general.model, messages: [ { role: "system", content: settings.general.system_role + prompt + referenceCurrentNoteContent2 || "You are a helpful assistant." }, ...messageHistoryAtIndex ], max_tokens: parseInt(settings.general.max_tokens) || 4096, temperature: parseInt(settings.general.temperature) }), signal: abortController.signal }); const data = await response.json(); let message = data.choices[0].message.content; const messageContainerEl2 = document.querySelector("#messageContainer"); if (messageContainerEl2) { const targetUserMessage = messageContainerElDivs[index2]; const targetBotMessage = targetUserMessage.nextElementSibling; const messageBlock = targetBotMessage == null ? void 0 : targetBotMessage.querySelector(".messageBlock"); const loadingEl = targetBotMessage == null ? void 0 : targetBotMessage.querySelector("#loading"); if (messageBlock) { if (loadingEl) { targetBotMessage == null ? void 0 : targetBotMessage.removeChild(loadingEl); } await import_obsidian4.MarkdownRenderer.render(plugin.app, message || "", messageBlock, "/", plugin); addParagraphBreaks(messageBlock); updateUnresolvedInternalLinks(plugin, messageBlock); const copyCodeBlocks = messageBlock.querySelectorAll(".copy-code-button"); copyCodeBlocks.forEach((copyCodeBlock) => { copyCodeBlock.textContent = "Copy"; (0, import_obsidian4.setIcon)(copyCodeBlock, "copy"); }); targetBotMessage == null ? void 0 : targetBotMessage.appendChild(messageBlock); } targetBotMessage == null ? void 0 : targetBotMessage.scrollIntoView({ behavior: "smooth", block: "start" }); } const regexPatterns = [ /[\s\S]*?<\/block-rendered>/g, /[\s\S]*?<\/note-rendered>/g ]; regexPatterns.forEach((pattern) => { message = message.replace(pattern, "").trim(); }); addMessage(plugin, message.trim(), "botMessage", settings, index2); return; } catch (error) { if (error.name === "AbortError") { console.log("Request aborted"); (0, import_obsidian4.setIcon)(submitButton, "arrow-up"); submitButton.title = "send"; if (messageContainerEl) { const targetUserMessage = messageContainerElDivs[index2]; const targetBotMessage = targetUserMessage.nextElementSibling; const messageBlock = targetBotMessage == null ? void 0 : targetBotMessage.querySelector(".messageBlock"); const loadingEl = targetBotMessage == null ? void 0 : targetBotMessage.querySelector("#loading"); if (messageBlock && loadingEl) { targetBotMessage == null ? void 0 : targetBotMessage.removeChild(loadingEl); messageBlock.textContent = "SYSTEM: Response aborted."; addMessage(plugin, "SYSTEM: Response aborted.", "botMessage", settings, index2); } } } else { const targetUserMessage = messageContainerElDivs[index2]; const targetBotMessage = targetUserMessage.nextElementSibling; targetBotMessage == null ? void 0 : targetBotMessage.remove(); const messageContainer = document.querySelector("#messageContainer"); const botMessageDiv2 = displayErrorBotMessage(plugin, settings, messageHistory, error); messageContainer.appendChild(botMessageDiv2); } } finally { abortController = null; } } async function fetchOpenRouterResponseStream(plugin, settings, index2) { const url = "https://openrouter.ai/api/v1/chat/completions"; abortController = new AbortController(); const prompt = await getPrompt(plugin, settings); let message = ""; let isScroll = false; const filteredMessageHistory = filterMessageHistory(messageHistory); const messageHistoryAtIndex = removeConsecutiveUserRoles(filteredMessageHistory); const messageContainerEl = document.querySelector("#messageContainer"); const messageContainerElDivs = document.querySelectorAll("#messageContainer div.userMessage, #messageContainer div.botMessage"); const botMessageDiv = displayLoadingBotMessage(settings); messageContainerEl == null ? void 0 : messageContainerEl.insertBefore(botMessageDiv, messageContainerElDivs[index2 + 1]); botMessageDiv.scrollIntoView({ behavior: "smooth", block: "start" }); await getActiveFileContent(plugin, settings); const referenceCurrentNoteContent2 = getCurrentNoteContent(); const submitButton = document.querySelector(".submit-button"); (0, import_obsidian4.setIcon)(submitButton, "square"); submitButton.title = "stop"; submitButton.addEventListener("click", () => { if (submitButton.title === "stop") { const controller = getAbortController(); if (controller) { controller.abort(); } } }); try { const response = await fetch(url, { method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${settings.APIConnections.openRouter.APIKey}` }, body: JSON.stringify({ model: settings.general.model, messages: [ { role: "system", content: settings.general.system_role + prompt + referenceCurrentNoteContent2 || "You are a helpful assistant." }, ...messageHistoryAtIndex ], stream: true, temperature: parseInt(settings.general.temperature), max_tokens: parseInt(settings.general.max_tokens) || 4096 }), signal: abortController.signal }); if (!response.ok) { new import_obsidian4.Notice(`HTTP error! Status: ${response.status}`); throw new Error(`HTTP error! Status: ${response.status}`); } if (!response.body) { new import_obsidian4.Notice("Response body is null or undefined."); throw new Error("Response body is null or undefined."); } const reader = response.body.getReader(); const decoder = new TextDecoder(); let reading = true; while (reading) { const { done, value } = await reader.read(); if (done) { reading = false; break; } const chunk = decoder.decode(value, { stream: false }) || ""; const parts = chunk.split("\n"); for (const part of parts.filter(Boolean)) { if (part.includes("data: [DONE]")) { break; } let parsedChunk; try { parsedChunk = JSON.parse(part.replace(/^data: /, "")); if (parsedChunk.choices[0].finish_reason !== "stop") { const content = parsedChunk.choices[0].delta.content; message += content; } } catch (err) { console.error("Error parsing JSON:", err); console.log("Part with error:", part); parsedChunk = { response: "{_e_}" }; } } const messageContainerEl2 = document.querySelector("#messageContainer"); if (messageContainerEl2) { const targetUserMessage = messageContainerElDivs[index2]; const targetBotMessage = targetUserMessage.nextElementSibling; const messageBlock = targetBotMessage == null ? void 0 : targetBotMessage.querySelector(".messageBlock"); const loadingEl = targetBotMessage == null ? void 0 : targetBotMessage.querySelector("#loading"); if (messageBlock) { if (loadingEl) { targetBotMessage == null ? void 0 : targetBotMessage.removeChild(loadingEl); } messageBlock.innerHTML = ""; const fragment = document.createDocumentFragment(); const tempContainer = document.createElement("div"); fragment.appendChild(tempContainer); await import_obsidian4.MarkdownRenderer.render(plugin.app, message, tempContainer, "/", plugin); while (tempContainer.firstChild) { messageBlock.appendChild(tempContainer.firstChild); } addParagraphBreaks(messageBlock); updateUnresolvedInternalLinks(plugin, messageBlock); const copyCodeBlocks = messageBlock.querySelectorAll(".copy-code-button"); copyCodeBlocks.forEach((copyCodeBlock) => { copyCodeBlock.textContent = "Copy"; (0, import_obsidian4.setIcon)(copyCodeBlock, "copy"); }); } messageContainerEl2.addEventListener("wheel", (event) => { if (event.deltaY < 0 || event.deltaY > 0) { isScroll = true; } }); if (!isScroll) { targetBotMessage == null ? void 0 : targetBotMessage.scrollIntoView({ behavior: "auto", block: "start" }); } } } const regexPatterns = [ /[\s\S]*?<\/block-rendered>/g, /[\s\S]*?<\/note-rendered>/g ]; regexPatterns.forEach((pattern) => { message = message.replace(pattern, "").trim(); }); addMessage(plugin, message.trim(), "botMessage", settings, index2); } catch (error) { addMessage(plugin, message.trim(), "botMessage", settings, index2); new import_obsidian4.Notice("Stream stopped."); console.error(error); } submitButton.textContent = "send"; (0, import_obsidian4.setIcon)(submitButton, "arrow-up"); submitButton.title = "send"; } function getAbortController() { return abortController; } function ollamaParametersOptions(settings) { return { mirostat: parseInt(settings.OllamaConnection.ollamaParameters.mirostat), mirostat_eta: parseFloat(settings.OllamaConnection.ollamaParameters.mirostat_eta), mirostat_tau: parseFloat(settings.OllamaConnection.ollamaParameters.mirostat_tau), num_ctx: parseInt(settings.OllamaConnection.ollamaParameters.num_ctx), num_gqa: parseInt(settings.OllamaConnection.ollamaParameters.num_gqa), num_thread: parseInt(settings.OllamaConnection.ollamaParameters.num_thread), repeat_last_n: parseInt(settings.OllamaConnection.ollamaParameters.repeat_last_n), repeat_penalty: parseFloat(settings.OllamaConnection.ollamaParameters.repeat_penalty), temperature: parseInt(settings.general.temperature), seed: parseInt(settings.OllamaConnection.ollamaParameters.seed), stop: settings.OllamaConnection.ollamaParameters.stop, tfs_z: parseFloat(settings.OllamaConnection.ollamaParameters.tfs_z), num_predict: parseInt(settings.general.max_tokens) || -1, top_k: parseInt(settings.OllamaConnection.ollamaParameters.top_k), top_p: parseFloat(settings.OllamaConnection.ollamaParameters.top_p), min_p: parseFloat(settings.OllamaConnection.ollamaParameters.min_p) }; } function filterMessageHistory(messageHistory2) { const skipIndexes = /* @__PURE__ */ new Set(); messageHistory2.forEach((message, index2, array) => { if (message.role === "user" && message.content.startsWith("/")) { skipIndexes.add(index2); if (index2 + 1 < array.length && array[index2 + 1].role === "assistant") { skipIndexes.add(index2 + 1); } } else if (message.role === "assistant" && message.content.includes("errorBotMessage")) { skipIndexes.add(index2); if (index2 > 0) { skipIndexes.add(index2 - 1); } } }); const filteredMessageHistory = messageHistory2.filter((_, index2) => !skipIndexes.has(index2)); return filteredMessageHistory; } function removeConsecutiveUserRoles(messageHistory2) { const result = []; let foundUserMessage = false; for (let i = 0; i < messageHistory2.length; i++) { if (messageHistory2[i].role === "user") { if (!foundUserMessage) { result.push(messageHistory2[i]); foundUserMessage = true; } else { break; } } else { result.push(messageHistory2[i]); foundUserMessage = false; } } return result; } // src/components/editor/FetchRenameNoteTitle.ts var import_obsidian5 = require("obsidian"); // node_modules/whatwg-fetch/fetch.js var g = typeof globalThis !== "undefined" && globalThis || typeof self !== "undefined" && self || // eslint-disable-next-line no-undef typeof global !== "undefined" && global || {}; var support = { searchParams: "URLSearchParams" in g, iterable: "Symbol" in g && "iterator" in Symbol, blob: "FileReader" in g && "Blob" in g && function() { try { new Blob(); return true; } catch (e) { return false; } }(), formData: "FormData" in g, arrayBuffer: "ArrayBuffer" in g }; function isDataView(obj) { return obj && DataView.prototype.isPrototypeOf(obj); } if (support.arrayBuffer) { viewClasses = [ "[object Int8Array]", "[object Uint8Array]", "[object Uint8ClampedArray]", "[object Int16Array]", "[object Uint16Array]", "[object Int32Array]", "[object Uint32Array]", "[object Float32Array]", "[object Float64Array]" ]; isArrayBufferView = ArrayBuffer.isView || function(obj) { return obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1; }; } var viewClasses; var isArrayBufferView; function normalizeName(name) { if (typeof name !== "string") { name = String(name); } if (/[^a-z0-9\-#$%&'*+.^_`|~!]/i.test(name) || name === "") { throw new TypeError('Invalid character in header field name: "' + name + '"'); } return name.toLowerCase(); } function normalizeValue(value) { if (typeof value !== "string") { value = String(value); } return value; } function iteratorFor(items) { var iterator = { next: function() { var value = items.shift(); return { done: value === void 0, value }; } }; if (support.iterable) { iterator[Symbol.iterator] = function() { return iterator; }; } return iterator; } function Headers2(headers) { this.map = {}; if (headers instanceof Headers2) { headers.forEach(function(value, name) { this.append(name, value); }, this); } else if (Array.isArray(headers)) { headers.forEach(function(header) { if (header.length != 2) { throw new TypeError("Headers constructor: expected name/value pair to be length 2, found" + header.length); } this.append(header[0], header[1]); }, this); } else if (headers) { Object.getOwnPropertyNames(headers).forEach(function(name) { this.append(name, headers[name]); }, this); } } Headers2.prototype.append = function(name, value) { name = normalizeName(name); value = normalizeValue(value); var oldValue = this.map[name]; this.map[name] = oldValue ? oldValue + ", " + value : value; }; Headers2.prototype["delete"] = function(name) { delete this.map[normalizeName(name)]; }; Headers2.prototype.get = function(name) { name = normalizeName(name); return this.has(name) ? this.map[name] : null; }; Headers2.prototype.has = function(name) { return this.map.hasOwnProperty(normalizeName(name)); }; Headers2.prototype.set = function(name, value) { this.map[normalizeName(name)] = normalizeValue(value); }; Headers2.prototype.forEach = function(callback, thisArg) { for (var name in this.map) { if (this.map.hasOwnProperty(name)) { callback.call(thisArg, this.map[name], name, this); } } }; Headers2.prototype.keys = function() { var items = []; this.forEach(function(value, name) { items.push(name); }); return iteratorFor(items); }; Headers2.prototype.values = function() { var items = []; this.forEach(function(value) { items.push(value); }); return iteratorFor(items); }; Headers2.prototype.entries = function() { var items = []; this.forEach(function(value, name) { items.push([name, value]); }); return iteratorFor(items); }; if (support.iterable) { Headers2.prototype[Symbol.iterator] = Headers2.prototype.entries; } function consumed(body) { if (body._noBody) return; if (body.bodyUsed) { return Promise.reject(new TypeError("Already read")); } body.bodyUsed = true; } function fileReaderReady(reader) { return new Promise(function(resolve2, reject) { reader.onload = function() { resolve2(reader.result); }; reader.onerror = function() { reject(reader.error); }; }); } function readBlobAsArrayBuffer(blob) { var reader = new FileReader(); var promise = fileReaderReady(reader); reader.readAsArrayBuffer(blob); return promise; } function readBlobAsText(blob) { var reader = new FileReader(); var promise = fileReaderReady(reader); var match = /charset=([A-Za-z0-9_-]+)/.exec(blob.type); var encoding = match ? match[1] : "utf-8"; reader.readAsText(blob, encoding); return promise; } function readArrayBufferAsText(buf) { var view = new Uint8Array(buf); var chars = new Array(view.length); for (var i = 0; i < view.length; i++) { chars[i] = String.fromCharCode(view[i]); } return chars.join(""); } function bufferClone(buf) { if (buf.slice) { return buf.slice(0); } else { var view = new Uint8Array(buf.byteLength); view.set(new Uint8Array(buf)); return view.buffer; } } function Body() { this.bodyUsed = false; this._initBody = function(body) { this.bodyUsed = this.bodyUsed; this._bodyInit = body; if (!body) { this._noBody = true; this._bodyText = ""; } else if (typeof body === "string") { this._bodyText = body; } else if (support.blob && Blob.prototype.isPrototypeOf(body)) { this._bodyBlob = body; } else if (support.formData && FormData.prototype.isPrototypeOf(body)) { this._bodyFormData = body; } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) { this._bodyText = body.toString(); } else if (support.arrayBuffer && support.blob && isDataView(body)) { this._bodyArrayBuffer = bufferClone(body.buffer); this._bodyInit = new Blob([this._bodyArrayBuffer]); } else if (support.arrayBuffer && (ArrayBuffer.prototype.isPrototypeOf(body) || isArrayBufferView(body))) { this._bodyArrayBuffer = bufferClone(body); } else { this._bodyText = body = Object.prototype.toString.call(body); } if (!this.headers.get("content-type")) { if (typeof body === "string") { this.headers.set("content-type", "text/plain;charset=UTF-8"); } else if (this._bodyBlob && this._bodyBlob.type) { this.headers.set("content-type", this._bodyBlob.type); } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) { this.headers.set("content-type", "application/x-www-form-urlencoded;charset=UTF-8"); } } }; if (support.blob) { this.blob = function() { var rejected = consumed(this); if (rejected) { return rejected; } if (this._bodyBlob) { return Promise.resolve(this._bodyBlob); } else if (this._bodyArrayBuffer) { return Promise.resolve(new Blob([this._bodyArrayBuffer])); } else if (this._bodyFormData) { throw new Error("could not read FormData body as blob"); } else { return Promise.resolve(new Blob([this._bodyText])); } }; } this.arrayBuffer = function() { if (this._bodyArrayBuffer) { var isConsumed = consumed(this); if (isConsumed) { return isConsumed; } else if (ArrayBuffer.isView(this._bodyArrayBuffer)) { return Promise.resolve( this._bodyArrayBuffer.buffer.slice( this._bodyArrayBuffer.byteOffset, this._bodyArrayBuffer.byteOffset + this._bodyArrayBuffer.byteLength ) ); } else { return Promise.resolve(this._bodyArrayBuffer); } } else if (support.blob) { return this.blob().then(readBlobAsArrayBuffer); } else { throw new Error("could not read as ArrayBuffer"); } }; this.text = function() { var rejected = consumed(this); if (rejected) { return rejected; } if (this._bodyBlob) { return readBlobAsText(this._bodyBlob); } else if (this._bodyArrayBuffer) { return Promise.resolve(readArrayBufferAsText(this._bodyArrayBuffer)); } else if (this._bodyFormData) { throw new Error("could not read FormData body as text"); } else { return Promise.resolve(this._bodyText); } }; if (support.formData) { this.formData = function() { return this.text().then(decode); }; } this.json = function() { return this.text().then(JSON.parse); }; return this; } var methods = ["CONNECT", "DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT", "TRACE"]; function normalizeMethod(method) { var upcased = method.toUpperCase(); return methods.indexOf(upcased) > -1 ? upcased : method; } function Request2(input, options) { if (!(this instanceof Request2)) { throw new TypeError('Please use the "new" operator, this DOM object constructor cannot be called as a function.'); } options = options || {}; var body = options.body; if (input instanceof Request2) { if (input.bodyUsed) { throw new TypeError("Already read"); } this.url = input.url; this.credentials = input.credentials; if (!options.headers) { this.headers = new Headers2(input.headers); } this.method = input.method; this.mode = input.mode; this.signal = input.signal; if (!body && input._bodyInit != null) { body = input._bodyInit; input.bodyUsed = true; } } else { this.url = String(input); } this.credentials = options.credentials || this.credentials || "same-origin"; if (options.headers || !this.headers) { this.headers = new Headers2(options.headers); } this.method = normalizeMethod(options.method || this.method || "GET"); this.mode = options.mode || this.mode || null; this.signal = options.signal || this.signal || function() { if ("AbortController" in g) { var ctrl = new AbortController(); return ctrl.signal; } }(); this.referrer = null; if ((this.method === "GET" || this.method === "HEAD") && body) { throw new TypeError("Body not allowed for GET or HEAD requests"); } this._initBody(body); if (this.method === "GET" || this.method === "HEAD") { if (options.cache === "no-store" || options.cache === "no-cache") { var reParamSearch = /([?&])_=[^&]*/; if (reParamSearch.test(this.url)) { this.url = this.url.replace(reParamSearch, "$1_=" + new Date().getTime()); } else { var reQueryString = /\?/; this.url += (reQueryString.test(this.url) ? "&" : "?") + "_=" + new Date().getTime(); } } } } Request2.prototype.clone = function() { return new Request2(this, { body: this._bodyInit }); }; function decode(body) { var form = new FormData(); body.trim().split("&").forEach(function(bytes) { if (bytes) { var split = bytes.split("="); var name = split.shift().replace(/\+/g, " "); var value = split.join("=").replace(/\+/g, " "); form.append(decodeURIComponent(name), decodeURIComponent(value)); } }); return form; } function parseHeaders(rawHeaders) { var headers = new Headers2(); var preProcessedHeaders = rawHeaders.replace(/\r?\n[\t ]+/g, " "); preProcessedHeaders.split("\r").map(function(header) { return header.indexOf("\n") === 0 ? header.substr(1, header.length) : header; }).forEach(function(line) { var parts = line.split(":"); var key = parts.shift().trim(); if (key) { var value = parts.join(":").trim(); try { headers.append(key, value); } catch (error) { console.warn("Response " + error.message); } } }); return headers; } Body.call(Request2.prototype); function Response2(bodyInit, options) { if (!(this instanceof Response2)) { throw new TypeError('Please use the "new" operator, this DOM object constructor cannot be called as a function.'); } if (!options) { options = {}; } this.type = "default"; this.status = options.status === void 0 ? 200 : options.status; if (this.status < 200 || this.status > 599) { throw new RangeError("Failed to construct 'Response': The status provided (0) is outside the range [200, 599]."); } this.ok = this.status >= 200 && this.status < 300; this.statusText = options.statusText === void 0 ? "" : "" + options.statusText; this.headers = new Headers2(options.headers); this.url = options.url || ""; this._initBody(bodyInit); } Body.call(Response2.prototype); Response2.prototype.clone = function() { return new Response2(this._bodyInit, { status: this.status, statusText: this.statusText, headers: new Headers2(this.headers), url: this.url }); }; Response2.error = function() { var response = new Response2(null, { status: 200, statusText: "" }); response.ok = false; response.status = 0; response.type = "error"; return response; }; var redirectStatuses = [301, 302, 303, 307, 308]; Response2.redirect = function(url, status) { if (redirectStatuses.indexOf(status) === -1) { throw new RangeError("Invalid status code"); } return new Response2(null, { status, headers: { location: url } }); }; var DOMException = g.DOMException; try { new DOMException(); } catch (err) { DOMException = function(message, name) { this.message = message; this.name = name; var error = Error(message); this.stack = error.stack; }; DOMException.prototype = Object.create(Error.prototype); DOMException.prototype.constructor = DOMException; } function fetch2(input, init) { return new Promise(function(resolve2, reject) { var request = new Request2(input, init); if (request.signal && request.signal.aborted) { return reject(new DOMException("Aborted", "AbortError")); } var xhr = new XMLHttpRequest(); function abortXhr() { xhr.abort(); } xhr.onload = function() { var options = { statusText: xhr.statusText, headers: parseHeaders(xhr.getAllResponseHeaders() || "") }; if (request.url.indexOf("file://") === 0 && (xhr.status < 200 || xhr.status > 599)) { options.status = 200; } else { options.status = xhr.status; } options.url = "responseURL" in xhr ? xhr.responseURL : options.headers.get("X-Request-URL"); var body = "response" in xhr ? xhr.response : xhr.responseText; setTimeout(function() { resolve2(new Response2(body, options)); }, 0); }; xhr.onerror = function() { setTimeout(function() { reject(new TypeError("Network request failed")); }, 0); }; xhr.ontimeout = function() { setTimeout(function() { reject(new TypeError("Network request timed out")); }, 0); }; xhr.onabort = function() { setTimeout(function() { reject(new DOMException("Aborted", "AbortError")); }, 0); }; function fixUrl(url) { try { return url === "" && g.location.href ? g.location.href : url; } catch (e) { return url; } } xhr.open(request.method, fixUrl(request.url), true); if (request.credentials === "include") { xhr.withCredentials = true; } else if (request.credentials === "omit") { xhr.withCredentials = false; } if ("responseType" in xhr) { if (support.blob) { xhr.responseType = "blob"; } else if (support.arrayBuffer) { xhr.responseType = "arraybuffer"; } } if (init && typeof init.headers === "object" && !(init.headers instanceof Headers2 || g.Headers && init.headers instanceof g.Headers)) { var names = []; Object.getOwnPropertyNames(init.headers).forEach(function(name) { names.push(normalizeName(name)); xhr.setRequestHeader(name, normalizeValue(init.headers[name])); }); request.headers.forEach(function(value, name) { if (names.indexOf(name) === -1) { xhr.setRequestHeader(name, value); } }); } else { request.headers.forEach(function(value, name) { xhr.setRequestHeader(name, value); }); } if (request.signal) { request.signal.addEventListener("abort", abortXhr); xhr.onreadystatechange = function() { if (xhr.readyState === 4) { request.signal.removeEventListener("abort", abortXhr); } }; } xhr.send(typeof request._bodyInit === "undefined" ? null : request._bodyInit); }); } fetch2.polyfill = true; if (!g.fetch) { g.fetch = fetch2; g.Headers = Headers2; g.Request = Request2; g.Response = Response2; } // node_modules/ollama/dist/shared/ollama.14e58652.mjs var version = "0.5.1"; var ResponseError = class extends Error { constructor(error, status_code) { super(error); this.error = error; this.status_code = status_code; this.name = "ResponseError"; if (Error.captureStackTrace) { Error.captureStackTrace(this, ResponseError); } } }; var checkOk = async (response) => { var _a2; if (!response.ok) { let message = `Error ${response.status}: ${response.statusText}`; let errorData = null; if ((_a2 = response.headers.get("content-type")) == null ? void 0 : _a2.includes("application/json")) { try { errorData = await response.json(); message = errorData.error || message; } catch (error) { console.log("Failed to parse error response as JSON"); } } else { try { console.log("Getting text from response"); const textResponse = await response.text(); message = textResponse || message; } catch (error) { console.log("Failed to get text from error response"); } } throw new ResponseError(message, response.status); } }; function getPlatform() { if (typeof window !== "undefined" && window.navigator) { return `${window.navigator.platform.toLowerCase()} Browser/${navigator.userAgent};`; } else if (typeof process !== "undefined") { return `${process.arch} ${process.platform} Node.js/${process.version}`; } return ""; } var fetchWithHeaders = async (fetch3, url, options = {}) => { const defaultHeaders = { "Content-Type": "application/json", Accept: "application/json", "User-Agent": `ollama-js/${version} (${getPlatform()})` }; if (!options.headers) { options.headers = {}; } options.headers = { ...defaultHeaders, ...options.headers }; return fetch3(url, options); }; var get = async (fetch3, host) => { const response = await fetchWithHeaders(fetch3, host); await checkOk(response); return response; }; var head = async (fetch3, host) => { const response = await fetchWithHeaders(fetch3, host, { method: "HEAD" }); await checkOk(response); return response; }; var post = async (fetch3, host, data, options) => { const isRecord = (input) => { return input !== null && typeof input === "object" && !Array.isArray(input); }; const formattedData = isRecord(data) ? JSON.stringify(data) : data; const response = await fetchWithHeaders(fetch3, host, { method: "POST", body: formattedData, signal: options == null ? void 0 : options.signal }); await checkOk(response); return response; }; var del = async (fetch3, host, data) => { const response = await fetchWithHeaders(fetch3, host, { method: "DELETE", body: JSON.stringify(data) }); await checkOk(response); return response; }; var parseJSON = async function* (itr) { var _a2; const decoder = new TextDecoder("utf-8"); let buffer = ""; const reader = itr.getReader(); while (true) { const { done, value: chunk } = await reader.read(); if (done) { break; } buffer += decoder.decode(chunk); const parts = buffer.split("\n"); buffer = (_a2 = parts.pop()) != null ? _a2 : ""; for (const part of parts) { try { yield JSON.parse(part); } catch (error) { console.warn("invalid json: ", part); } } } for (const part of buffer.split("\n").filter((p) => p !== "")) { try { yield JSON.parse(part); } catch (error) { console.warn("invalid json: ", part); } } }; var formatHost = (host) => { if (!host) { return "http://127.0.0.1:11434"; } let isExplicitProtocol = host.includes("://"); if (host.startsWith(":")) { host = `http://127.0.0.1${host}`; isExplicitProtocol = false; } if (!isExplicitProtocol) { host = `http://${host}`; } const url = new URL(host); let port = url.port; if (!port) { if (!isExplicitProtocol) { port = "11434"; } else { port = url.protocol === "https:" ? "443" : "80"; } } let formattedHost = `${url.protocol}//${url.hostname}:${port}${url.pathname}`; if (formattedHost.endsWith("/")) { formattedHost = formattedHost.slice(0, -1); } return formattedHost; }; var __defProp2 = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField = (obj, key, value) => { __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; var Ollama$1 = class Ollama { constructor(config) { var _a2; __publicField(this, "config"); __publicField(this, "fetch"); __publicField(this, "abortController"); this.config = { host: "" }; if (!(config == null ? void 0 : config.proxy)) { this.config.host = formatHost((_a2 = config == null ? void 0 : config.host) != null ? _a2 : "http://127.0.0.1:11434"); } this.fetch = fetch; if ((config == null ? void 0 : config.fetch) != null) { this.fetch = config.fetch; } this.abortController = new AbortController(); } // Abort any ongoing requests to Ollama abort() { this.abortController.abort(); this.abortController = new AbortController(); } async processStreamableRequest(endpoint, request) { var _a2; request.stream = (_a2 = request.stream) != null ? _a2 : false; const response = await post( this.fetch, `${this.config.host}/api/${endpoint}`, { ...request }, { signal: this.abortController.signal } ); if (!response.body) { throw new Error("Missing body"); } const itr = parseJSON(response.body); if (request.stream) { return async function* () { for await (const message of itr) { if ("error" in message) { throw new Error(message.error); } yield message; if (message.done || message.status === "success") { return; } } throw new Error("Did not receive done or success response in stream."); }(); } else { const message = await itr.next(); if (!message.value.done && message.value.status !== "success") { throw new Error("Expected a completed response."); } return message.value; } } async encodeImage(image) { if (typeof image !== "string") { const uint8Array = new Uint8Array(image); const numberArray = Array.from(uint8Array); const base64String = btoa(String.fromCharCode.apply(null, numberArray)); return base64String; } return image; } async generate(request) { if (request.images) { request.images = await Promise.all(request.images.map(this.encodeImage.bind(this))); } return this.processStreamableRequest("generate", request); } async chat(request) { if (request.messages) { for (const message of request.messages) { if (message.images) { message.images = await Promise.all( message.images.map(this.encodeImage.bind(this)) ); } } } return this.processStreamableRequest("chat", request); } async create(request) { return this.processStreamableRequest("create", { name: request.model, stream: request.stream, modelfile: request.modelfile, quantize: request.quantize }); } async pull(request) { return this.processStreamableRequest("pull", { name: request.model, stream: request.stream, insecure: request.insecure }); } async push(request) { return this.processStreamableRequest("push", { name: request.model, stream: request.stream, insecure: request.insecure }); } async delete(request) { await del(this.fetch, `${this.config.host}/api/delete`, { name: request.model }); return { status: "success" }; } async copy(request) { await post(this.fetch, `${this.config.host}/api/copy`, { ...request }); return { status: "success" }; } async list() { const response = await get(this.fetch, `${this.config.host}/api/tags`); const listResponse = await response.json(); return listResponse; } async show(request) { const response = await post(this.fetch, `${this.config.host}/api/show`, { ...request }); const showResponse = await response.json(); return showResponse; } async embeddings(request) { const response = await post(this.fetch, `${this.config.host}/api/embeddings`, { ...request }); const embeddingsResponse = await response.json(); return embeddingsResponse; } }; var browser = new Ollama$1(); // node_modules/ollama/dist/index.mjs var import_fs = __toESM(require("fs"), 1); var import_path = require("path"); var import_crypto = require("crypto"); var import_os = require("os"); var Ollama2 = class extends Ollama$1 { async encodeImage(image) { if (typeof image !== "string") { const result = Buffer.from(image).toString("base64"); return result; } try { if (import_fs.default.existsSync(image)) { const fileBuffer = await import_fs.promises.readFile((0, import_path.resolve)(image)); return Buffer.from(fileBuffer).toString("base64"); } } catch (e) { } return image; } async parseModelfile(modelfile, mfDir = process.cwd()) { const out = []; const lines = modelfile.split("\n"); for (const line of lines) { const [command, args] = line.split(" ", 2); if (["FROM", "ADAPTER"].includes(command.toUpperCase())) { const path = this.resolvePath(args.trim(), mfDir); if (await this.fileExists(path)) { out.push(`${command} @${await this.createBlob(path)}`); } else { out.push(`${command} ${args}`); } } else { out.push(line); } } return out.join("\n"); } resolvePath(inputPath, mfDir) { if (inputPath.startsWith("~")) { return (0, import_path.join)((0, import_os.homedir)(), inputPath.slice(1)); } return (0, import_path.resolve)(mfDir, inputPath); } async fileExists(path) { try { await import_fs.promises.access(path); return true; } catch (e) { return false; } } async createBlob(path) { if (typeof ReadableStream === "undefined") { throw new Error("Streaming uploads are not supported in this environment."); } const fileStream = (0, import_fs.createReadStream)(path); const sha256sum = await new Promise((resolve2, reject) => { const hash = (0, import_crypto.createHash)("sha256"); fileStream.on("data", (data) => hash.update(data)); fileStream.on("end", () => resolve2(hash.digest("hex"))); fileStream.on("error", reject); }); const digest = `sha256:${sha256sum}`; try { await head(this.fetch, `${this.config.host}/api/blobs/${digest}`); } catch (e) { if (e instanceof Error && e.message.includes("404")) { const readableStream = new ReadableStream({ start(controller) { fileStream.on("data", (chunk) => { controller.enqueue(chunk); }); fileStream.on("end", () => { controller.close(); }); fileStream.on("error", (err) => { controller.error(err); }); } }); await post( this.fetch, `${this.config.host}/api/blobs/${digest}`, readableStream ); } else { throw e; } } return digest; } async create(request) { let modelfileContent = ""; if (request.path) { modelfileContent = await import_fs.promises.readFile(request.path, { encoding: "utf8" }); modelfileContent = await this.parseModelfile( modelfileContent, (0, import_path.dirname)(request.path) ); } else if (request.modelfile) { modelfileContent = await this.parseModelfile(request.modelfile); } else { throw new Error("Must provide either path or modelfile to create a model"); } request.modelfile = modelfileContent; if (request.stream) { return super.create(request); } else { return super.create(request); } } }; var index = new Ollama2(); // node_modules/openai/version.mjs var VERSION = "4.6.0"; // node_modules/openai/streaming.mjs var Stream = class { constructor(response, controller) { this.response = response; this.controller = controller; this.decoder = new SSEDecoder(); } async *iterMessages() { if (!this.response.body) { this.controller.abort(); throw new Error(`Attempted to iterate over a response with no body`); } const lineDecoder = new LineDecoder(); const iter = readableStreamAsyncIterable(this.response.body); for await (const chunk of iter) { for (const line of lineDecoder.decode(chunk)) { const sse = this.decoder.decode(line); if (sse) yield sse; } } for (const line of lineDecoder.flush()) { const sse = this.decoder.decode(line); if (sse) yield sse; } } async *[Symbol.asyncIterator]() { let done = false; try { for await (const sse of this.iterMessages()) { if (done) continue; if (sse.data.startsWith("[DONE]")) { done = true; continue; } if (sse.event === null) { try { yield JSON.parse(sse.data); } catch (e) { console.error(`Could not parse message into JSON:`, sse.data); console.error(`From chunk:`, sse.raw); throw e; } } } done = true; } catch (e) { if (e instanceof Error && e.name === "AbortError") return; throw e; } finally { if (!done) this.controller.abort(); } } }; var SSEDecoder = class { constructor() { this.event = null; this.data = []; this.chunks = []; } decode(line) { if (line.endsWith("\r")) { line = line.substring(0, line.length - 1); } if (!line) { if (!this.event && !this.data.length) return null; const sse = { event: this.event, data: this.data.join("\n"), raw: this.chunks }; this.event = null; this.data = []; this.chunks = []; return sse; } this.chunks.push(line); if (line.startsWith(":")) { return null; } let [fieldname, _, value] = partition(line, ":"); if (value.startsWith(" ")) { value = value.substring(1); } if (fieldname === "event") { this.event = value; } else if (fieldname === "data") { this.data.push(value); } return null; } }; var LineDecoder = class { constructor() { this.buffer = []; this.trailingCR = false; } decode(chunk) { let text = this.decodeText(chunk); if (this.trailingCR) { text = "\r" + text; this.trailingCR = false; } if (text.endsWith("\r")) { this.trailingCR = true; text = text.slice(0, -1); } if (!text) { return []; } const trailingNewline = LineDecoder.NEWLINE_CHARS.has(text[text.length - 1] || ""); let lines = text.split(LineDecoder.NEWLINE_REGEXP); if (lines.length === 1 && !trailingNewline) { this.buffer.push(lines[0]); return []; } if (this.buffer.length > 0) { lines = [this.buffer.join("") + lines[0], ...lines.slice(1)]; this.buffer = []; } if (!trailingNewline) { this.buffer = [lines.pop() || ""]; } return lines; } decodeText(bytes) { var _a2; if (bytes == null) return ""; if (typeof bytes === "string") return bytes; if (typeof Buffer !== "undefined") { if (bytes instanceof Buffer) { return bytes.toString(); } if (bytes instanceof Uint8Array) { return Buffer.from(bytes).toString(); } throw new Error( `Unexpected: received non-Uint8Array (${bytes.constructor.name}) stream chunk in an environment with a global "Buffer" defined, which this library assumes to be Node. Please report this error.` ); } if (typeof TextDecoder !== "undefined") { if (bytes instanceof Uint8Array || bytes instanceof ArrayBuffer) { (_a2 = this.textDecoder) !== null && _a2 !== void 0 ? _a2 : this.textDecoder = new TextDecoder("utf8"); return this.textDecoder.decode(bytes); } throw new Error( `Unexpected: received non-Uint8Array/ArrayBuffer (${bytes.constructor.name}) in a web platform. Please report this error.` ); } throw new Error( `Unexpected: neither Buffer nor TextDecoder are available as globals. Please report this error.` ); } flush() { if (!this.buffer.length && !this.trailingCR) { return []; } const lines = [this.buffer.join("")]; this.buffer = []; this.trailingCR = false; return lines; } }; LineDecoder.NEWLINE_CHARS = /* @__PURE__ */ new Set(["\n", "\r", "\v", "\f", "", "", "", "\x85", "\u2028", "\u2029"]); LineDecoder.NEWLINE_REGEXP = /\r\n|[\n\r\x0b\x0c\x1c\x1d\x1e\x85\u2028\u2029]/g; function partition(str, delimiter) { const index2 = str.indexOf(delimiter); if (index2 !== -1) { return [str.substring(0, index2), delimiter, str.substring(index2 + delimiter.length)]; } return [str, "", ""]; } function readableStreamAsyncIterable(stream) { if (stream[Symbol.asyncIterator]) return stream; const reader = stream.getReader(); return { async next() { try { const result = await reader.read(); if (result === null || result === void 0 ? void 0 : result.done) reader.releaseLock(); return result; } catch (e) { reader.releaseLock(); throw e; } }, async return() { const cancelPromise = reader.cancel(); reader.releaseLock(); await cancelPromise; return { done: true, value: void 0 }; }, [Symbol.asyncIterator]() { return this; } }; } // node_modules/openai/error.mjs var error_exports = {}; __export(error_exports, { APIConnectionError: () => APIConnectionError, APIConnectionTimeoutError: () => APIConnectionTimeoutError, APIError: () => APIError, APIUserAbortError: () => APIUserAbortError, AuthenticationError: () => AuthenticationError, BadRequestError: () => BadRequestError, ConflictError: () => ConflictError, InternalServerError: () => InternalServerError, NotFoundError: () => NotFoundError, PermissionDeniedError: () => PermissionDeniedError, RateLimitError: () => RateLimitError, UnprocessableEntityError: () => UnprocessableEntityError }); var APIError = class extends Error { constructor(status, error, message, headers) { super(APIError.makeMessage(error, message)); this.status = status; this.headers = headers; const data = error; this.error = data; this.code = data === null || data === void 0 ? void 0 : data["code"]; this.param = data === null || data === void 0 ? void 0 : data["param"]; this.type = data === null || data === void 0 ? void 0 : data["type"]; } static makeMessage(error, message) { return (error === null || error === void 0 ? void 0 : error.message) ? typeof error.message === "string" ? error.message : JSON.stringify(error.message) : error ? JSON.stringify(error) : message || "Unknown error occurred"; } static generate(status, errorResponse, message, headers) { if (!status) { return new APIConnectionError({ cause: castToError(errorResponse) }); } const error = errorResponse === null || errorResponse === void 0 ? void 0 : errorResponse["error"]; if (status === 400) { return new BadRequestError(status, error, message, headers); } if (status === 401) { return new AuthenticationError(status, error, message, headers); } if (status === 403) { return new PermissionDeniedError(status, error, message, headers); } if (status === 404) { return new NotFoundError(status, error, message, headers); } if (status === 409) { return new ConflictError(status, error, message, headers); } if (status === 422) { return new UnprocessableEntityError(status, error, message, headers); } if (status === 429) { return new RateLimitError(status, error, message, headers); } if (status >= 500) { return new InternalServerError(status, error, message, headers); } return new APIError(status, error, message, headers); } }; var APIUserAbortError = class extends APIError { constructor({ message } = {}) { super(void 0, void 0, message || "Request was aborted.", void 0); this.status = void 0; } }; var APIConnectionError = class extends APIError { constructor({ message, cause }) { super(void 0, void 0, message || "Connection error.", void 0); this.status = void 0; if (cause) this.cause = cause; } }; var APIConnectionTimeoutError = class extends APIConnectionError { constructor({ message } = {}) { super({ message: message !== null && message !== void 0 ? message : "Request timed out." }); } }; var BadRequestError = class extends APIError { constructor() { super(...arguments); this.status = 400; } }; var AuthenticationError = class extends APIError { constructor() { super(...arguments); this.status = 401; } }; var PermissionDeniedError = class extends APIError { constructor() { super(...arguments); this.status = 403; } }; var NotFoundError = class extends APIError { constructor() { super(...arguments); this.status = 404; } }; var ConflictError = class extends APIError { constructor() { super(...arguments); this.status = 409; } }; var UnprocessableEntityError = class extends APIError { constructor() { super(...arguments); this.status = 422; } }; var RateLimitError = class extends APIError { constructor() { super(...arguments); this.status = 429; } }; var InternalServerError = class extends APIError { }; // node_modules/openai/_shims/agent.mjs var getDefaultAgent = (url) => { return void 0; }; // node_modules/openai/_shims/fetch.mjs var _fetch = fetch.bind(void 0); var isPolyfilled = false; // node_modules/openai/_shims/form-data.mjs var _FormData = FormData; var _File = typeof File !== "undefined" ? File : ( // Bun doesn't implement File yet, so just make a shim that throws a helpful error message class File2 extends Blob { constructor() { throw new Error(`file uploads aren't supported in this environment yet as 'File' is not defined`); } } ); // node_modules/openai/_shims/getMultipartRequestOptions.mjs async function getMultipartRequestOptions(form, opts) { return { ...opts, body: new MultipartBody(form) }; } // node_modules/openai/_shims/fileFromPath.mjs async function fileFromPath() { throw new Error( "The `fileFromPath` function is only supported in Node. See the README for more details: https://www.github.com/openai/openai-node#file-uploads" ); } // node_modules/openai/_shims/node-readable.mjs function isFsReadStream(value) { return false; } // node_modules/openai/uploads.mjs var isResponseLike = (value) => value != null && typeof value === "object" && typeof value.url === "string" && typeof value.blob === "function"; var isFileLike = (value) => value != null && typeof value === "object" && typeof value.name === "string" && typeof value.lastModified === "number" && isBlobLike(value); var isBlobLike = (value) => value != null && typeof value === "object" && typeof value.size === "number" && typeof value.type === "string" && typeof value.text === "function" && typeof value.slice === "function" && typeof value.arrayBuffer === "function"; var isUploadable = (value) => { return isFileLike(value) || isResponseLike(value) || isFsReadStream(value); }; async function toFile(value, name, options = {}) { var _a2, _b, _c; value = await value; if (isResponseLike(value)) { const blob = await value.blob(); name || (name = (_a2 = new URL(value.url).pathname.split(/[\\/]/).pop()) !== null && _a2 !== void 0 ? _a2 : "unknown_file"); return new _File([blob], name, options); } const bits = await getBytes(value); name || (name = (_b = getName(value)) !== null && _b !== void 0 ? _b : "unknown_file"); if (!options.type) { const type = (_c = bits[0]) === null || _c === void 0 ? void 0 : _c.type; if (typeof type === "string") { options = { ...options, type }; } } return new _File(bits, name, options); } async function getBytes(value) { var _a2; let parts = []; if (typeof value === "string" || ArrayBuffer.isView(value) || // includes Uint8Array, Buffer, etc. value instanceof ArrayBuffer) { parts.push(value); } else if (isBlobLike(value)) { parts.push(await value.arrayBuffer()); } else if (isAsyncIterableIterator(value)) { for await (const chunk of value) { parts.push(chunk); } } else { throw new Error( `Unexpected data type: ${typeof value}; constructor: ${(_a2 = value === null || value === void 0 ? void 0 : value.constructor) === null || _a2 === void 0 ? void 0 : _a2.name}; props: ${propsForError(value)}` ); } return parts; } function propsForError(value) { const props = Object.getOwnPropertyNames(value); return `[${props.map((p) => `"${p}"`).join(", ")}]`; } function getName(value) { var _a2; return getStringFromMaybeBuffer(value.name) || getStringFromMaybeBuffer(value.filename) || // For fs.ReadStream ((_a2 = getStringFromMaybeBuffer(value.path)) === null || _a2 === void 0 ? void 0 : _a2.split(/[\\/]/).pop()); } var getStringFromMaybeBuffer = (x) => { if (typeof x === "string") return x; if (typeof Buffer !== "undefined" && x instanceof Buffer) return String(x); return void 0; }; var isAsyncIterableIterator = (value) => value != null && typeof value === "object" && typeof value[Symbol.asyncIterator] === "function"; var MultipartBody = class { constructor(body) { this.body = body; } get [Symbol.toStringTag]() { return "MultipartBody"; } }; var isMultipartBody = (body) => body && typeof body === "object" && body.body && body[Symbol.toStringTag] === "MultipartBody"; var multipartFormRequestOptions = async (opts) => { const form = await createForm(opts.body); return getMultipartRequestOptions(form, opts); }; var createForm = async (body) => { const form = new _FormData(); await Promise.all(Object.entries(body || {}).map(([key, value]) => addFormValue(form, key, value))); return form; }; var addFormValue = async (form, key, value) => { if (value === void 0) return; if (value == null) { throw new TypeError( `Received null for "${key}"; to pass null in FormData, you must use the string 'null'` ); } if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") { form.append(key, String(value)); } else if (isUploadable(value)) { const file = await toFile(value); form.append(key, file); } else if (Array.isArray(value)) { await Promise.all(value.map((entry) => addFormValue(form, key + "[]", entry))); } else if (typeof value === "object") { await Promise.all( Object.entries(value).map(([name, prop]) => addFormValue(form, `${key}[${name}]`, prop)) ); } else { throw new TypeError( `Invalid value given to form, expected a string, number, boolean, object, Array, File or Blob but got ${value} instead` ); } }; // node_modules/openai/core.mjs var __classPrivateFieldSet = function(receiver, state, value, kind, f) { if (kind === "m") throw new TypeError("Private method is not writable"); if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); return kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value; }; var __classPrivateFieldGet = function(receiver, state, kind, f) { if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); }; var _AbstractPage_client; var MAX_RETRIES = 2; async function defaultParseResponse(props) { const { response } = props; if (props.options.stream) { return new Stream(response, props.controller); } const contentType = response.headers.get("content-type"); if (contentType === null || contentType === void 0 ? void 0 : contentType.includes("application/json")) { const json = await response.json(); debug("response", response.status, response.url, response.headers, json); return json; } const text = await response.text(); debug("response", response.status, response.url, response.headers, text); return text; } var APIPromise = class extends Promise { constructor(responsePromise, parseResponse = defaultParseResponse) { super((resolve2) => { resolve2(null); }); this.responsePromise = responsePromise; this.parseResponse = parseResponse; } _thenUnwrap(transform) { return new APIPromise(this.responsePromise, async (props) => transform(await this.parseResponse(props))); } /** * Gets the raw `Response` instance instead of parsing the response * data. * * If you want to parse the response body but still get the `Response` * instance, you can use {@link withResponse()}. */ asResponse() { return this.responsePromise.then((p) => p.response); } /** * Gets the parsed response data and the raw `Response` instance. * * If you just want to get the raw `Response` instance without parsing it, * you can use {@link asResponse()}. */ async withResponse() { const [data, response] = await Promise.all([this.parse(), this.asResponse()]); return { data, response }; } parse() { if (!this.parsedPromise) { this.parsedPromise = this.responsePromise.then(this.parseResponse); } return this.parsedPromise; } then(onfulfilled, onrejected) { return this.parse().then(onfulfilled, onrejected); } catch(onrejected) { return this.parse().catch(onrejected); } finally(onfinally) { return this.parse().finally(onfinally); } }; var APIClient = class { constructor({ baseURL, maxRetries, timeout = 6e5, // 10 minutes httpAgent, fetch: overridenFetch }) { this.baseURL = baseURL; this.maxRetries = validatePositiveInteger( "maxRetries", maxRetries !== null && maxRetries !== void 0 ? maxRetries : MAX_RETRIES ); this.timeout = validatePositiveInteger("timeout", timeout); this.httpAgent = httpAgent; this.fetch = overridenFetch !== null && overridenFetch !== void 0 ? overridenFetch : _fetch; } authHeaders(opts) { return {}; } /** * Override this to add your own default headers, for example: * * { * ...super.defaultHeaders(), * Authorization: 'Bearer 123', * } */ defaultHeaders(opts) { return { Accept: "application/json", "Content-Type": "application/json", "User-Agent": this.getUserAgent(), ...getPlatformHeaders(), ...this.authHeaders(opts) }; } /** * Override this to add your own headers validation: */ validateHeaders(headers, customHeaders) { } defaultIdempotencyKey() { return `stainless-node-retry-${uuid4()}`; } get(path, opts) { return this.methodRequest("get", path, opts); } post(path, opts) { return this.methodRequest("post", path, opts); } patch(path, opts) { return this.methodRequest("patch", path, opts); } put(path, opts) { return this.methodRequest("put", path, opts); } delete(path, opts) { return this.methodRequest("delete", path, opts); } methodRequest(method, path, opts) { return this.request(Promise.resolve(opts).then((opts2) => ({ method, path, ...opts2 }))); } getAPIList(path, Page2, opts) { return this.requestAPIList(Page2, { method: "get", path, ...opts }); } calculateContentLength(body) { if (typeof body === "string") { if (typeof Buffer !== "undefined") { return Buffer.byteLength(body, "utf8").toString(); } if (typeof TextEncoder !== "undefined") { const encoder = new TextEncoder(); const encoded = encoder.encode(body); return encoded.length.toString(); } } return null; } buildRequest(options) { var _a2, _b, _c, _d, _e, _f; const { method, path, query, headers = {} } = options; const body = isMultipartBody(options.body) ? options.body.body : options.body ? JSON.stringify(options.body, null, 2) : null; const contentLength = this.calculateContentLength(body); const url = this.buildURL(path, query); if ("timeout" in options) validatePositiveInteger("timeout", options.timeout); const timeout = (_a2 = options.timeout) !== null && _a2 !== void 0 ? _a2 : this.timeout; const httpAgent = (_c = (_b = options.httpAgent) !== null && _b !== void 0 ? _b : this.httpAgent) !== null && _c !== void 0 ? _c : getDefaultAgent(url); const minAgentTimeout = timeout + 1e3; if (typeof ((_d = httpAgent === null || httpAgent === void 0 ? void 0 : httpAgent.options) === null || _d === void 0 ? void 0 : _d.timeout) === "number" && minAgentTimeout > ((_e = httpAgent.options.timeout) !== null && _e !== void 0 ? _e : 0)) { httpAgent.options.timeout = minAgentTimeout; } if (this.idempotencyHeader && method !== "get") { if (!options.idempotencyKey) options.idempotencyKey = this.defaultIdempotencyKey(); headers[this.idempotencyHeader] = options.idempotencyKey; } const reqHeaders = { ...contentLength && { "Content-Length": contentLength }, ...this.defaultHeaders(options), ...headers }; if (isMultipartBody(options.body) && !isPolyfilled) { delete reqHeaders["Content-Type"]; } Object.keys(reqHeaders).forEach((key) => reqHeaders[key] === null && delete reqHeaders[key]); const req = { method, ...body && { body }, headers: reqHeaders, ...httpAgent && { agent: httpAgent }, // @ts-ignore node-fetch uses a custom AbortSignal type that is // not compatible with standard web types signal: (_f = options.signal) !== null && _f !== void 0 ? _f : null }; this.validateHeaders(reqHeaders, headers); return { req, url, timeout }; } /** * Used as a callback for mutating the given `RequestInit` object. * * This is useful for cases where you want to add certain headers based off of * the request properties, e.g. `method` or `url`. */ async prepareRequest(request, { url, options }) { } parseHeaders(headers) { return !headers ? {} : Symbol.iterator in headers ? Object.fromEntries(Array.from(headers).map((header) => [...header])) : { ...headers }; } makeStatusError(status, error, message, headers) { return APIError.generate(status, error, message, headers); } request(options, remainingRetries = null) { return new APIPromise(this.makeRequest(options, remainingRetries)); } async makeRequest(optionsInput, retriesRemaining) { var _a2, _b, _c; const options = await optionsInput; if (retriesRemaining == null) { retriesRemaining = (_a2 = options.maxRetries) !== null && _a2 !== void 0 ? _a2 : this.maxRetries; } const { req, url, timeout } = this.buildRequest(options); await this.prepareRequest(req, { url, options }); debug("request", url, options, req.headers); if ((_b = options.signal) === null || _b === void 0 ? void 0 : _b.aborted) { throw new APIUserAbortError(); } const controller = new AbortController(); const response = await this.fetchWithTimeout(url, req, timeout, controller).catch(castToError); if (response instanceof Error) { if ((_c = options.signal) === null || _c === void 0 ? void 0 : _c.aborted) { throw new APIUserAbortError(); } if (retriesRemaining) { return this.retryRequest(options, retriesRemaining); } if (response.name === "AbortError") { throw new APIConnectionTimeoutError(); } throw new APIConnectionError({ cause: response }); } const responseHeaders = createResponseHeaders(response.headers); if (!response.ok) { if (retriesRemaining && this.shouldRetry(response)) { return this.retryRequest(options, retriesRemaining, responseHeaders); } const errText = await response.text().catch(() => "Unknown"); const errJSON = safeJSON(errText); const errMessage = errJSON ? void 0 : errText; debug("response", response.status, url, responseHeaders, errMessage); const err = this.makeStatusError(response.status, errJSON, errMessage, responseHeaders); throw err; } return { response, options, controller }; } requestAPIList(Page2, options) { const request = this.makeRequest(options, null); return new PagePromise(this, request, Page2); } buildURL(path, query) { const url = isAbsoluteURL(path) ? new URL(path) : new URL(this.baseURL + (this.baseURL.endsWith("/") && path.startsWith("/") ? path.slice(1) : path)); const defaultQuery = this.defaultQuery(); if (!isEmptyObj(defaultQuery)) { query = { ...defaultQuery, ...query }; } if (query) { url.search = this.stringifyQuery(query); } return url.toString(); } stringifyQuery(query) { return Object.entries(query).filter(([_, value]) => typeof value !== "undefined").map(([key, value]) => { if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") { return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`; } if (value === null) { return `${encodeURIComponent(key)}=`; } throw new Error( `Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.` ); }).join("&"); } async fetchWithTimeout(url, init, ms, controller) { const { signal, ...options } = init || {}; if (signal) signal.addEventListener("abort", () => controller.abort()); const timeout = setTimeout(() => controller.abort(), ms); return this.getRequestClient().fetch(url, { signal: controller.signal, ...options }).finally(() => { clearTimeout(timeout); }); } getRequestClient() { return { fetch: this.fetch }; } shouldRetry(response) { const shouldRetryHeader = response.headers.get("x-should-retry"); if (shouldRetryHeader === "true") return true; if (shouldRetryHeader === "false") return false; if (response.status === 409) return true; if (response.status === 429) return true; if (response.status >= 500) return true; return false; } async retryRequest(options, retriesRemaining, responseHeaders) { var _a2; retriesRemaining -= 1; const retryAfter = parseInt( (responseHeaders === null || responseHeaders === void 0 ? void 0 : responseHeaders["retry-after"]) || "" ); const maxRetries = (_a2 = options.maxRetries) !== null && _a2 !== void 0 ? _a2 : this.maxRetries; const timeout = this.calculateRetryTimeoutSeconds(retriesRemaining, retryAfter, maxRetries) * 1e3; await sleep(timeout); return this.makeRequest(options, retriesRemaining); } calculateRetryTimeoutSeconds(retriesRemaining, retryAfter, maxRetries) { const initialRetryDelay = 0.5; const maxRetryDelay = 2; if (Number.isInteger(retryAfter) && retryAfter <= 60) { return retryAfter; } const numRetries = maxRetries - retriesRemaining; const sleepSeconds = Math.min(initialRetryDelay * Math.pow(numRetries - 1, 2), maxRetryDelay); const jitter = Math.random() - 0.5; return sleepSeconds + jitter; } getUserAgent() { return `${this.constructor.name}/JS ${VERSION}`; } }; var AbstractPage = class { constructor(client, response, body, options) { _AbstractPage_client.set(this, void 0); __classPrivateFieldSet(this, _AbstractPage_client, client, "f"); this.options = options; this.response = response; this.body = body; } hasNextPage() { const items = this.getPaginatedItems(); if (!items.length) return false; return this.nextPageInfo() != null; } async getNextPage() { const nextInfo = this.nextPageInfo(); if (!nextInfo) { throw new Error( "No next page expected; please check `.hasNextPage()` before calling `.getNextPage()`." ); } const nextOptions = { ...this.options }; if ("params" in nextInfo) { nextOptions.query = { ...nextOptions.query, ...nextInfo.params }; } else if ("url" in nextInfo) { const params = [...Object.entries(nextOptions.query || {}), ...nextInfo.url.searchParams.entries()]; for (const [key, value] of params) { nextInfo.url.searchParams.set(key, value); } nextOptions.query = void 0; nextOptions.path = nextInfo.url.toString(); } return await __classPrivateFieldGet(this, _AbstractPage_client, "f").requestAPIList( this.constructor, nextOptions ); } async *iterPages() { let page = this; yield page; while (page.hasNextPage()) { page = await page.getNextPage(); yield page; } } async *[(_AbstractPage_client = /* @__PURE__ */ new WeakMap(), Symbol.asyncIterator)]() { for await (const page of this.iterPages()) { for (const item of page.getPaginatedItems()) { yield item; } } } }; var PagePromise = class extends APIPromise { constructor(client, request, Page2) { super( request, async (props) => new Page2(client, props.response, await defaultParseResponse(props), props.options) ); } /** * Allow auto-paginating iteration on an unawaited list call, eg: * * for await (const item of client.items.list()) { * console.log(item) * } */ async *[Symbol.asyncIterator]() { const page = await this; for await (const item of page) { yield item; } } }; var createResponseHeaders = (headers) => { return new Proxy( Object.fromEntries( // @ts-ignore headers.entries() ), { get(target, name) { const key = name.toString(); return target[key.toLowerCase()] || target[key]; } } ); }; var requestOptionsKeys = { method: true, path: true, query: true, body: true, headers: true, maxRetries: true, stream: true, timeout: true, httpAgent: true, signal: true, idempotencyKey: true }; var isRequestOptions = (obj) => { return typeof obj === "object" && obj !== null && !isEmptyObj(obj) && Object.keys(obj).every((k) => hasOwn(requestOptionsKeys, k)); }; var getPlatformProperties = () => { if (typeof Deno !== "undefined" && Deno.build != null) { return { "X-Stainless-Lang": "js", "X-Stainless-Package-Version": VERSION, "X-Stainless-OS": normalizePlatform(Deno.build.os), "X-Stainless-Arch": normalizeArch(Deno.build.arch), "X-Stainless-Runtime": "deno", "X-Stainless-Runtime-Version": Deno.version }; } if (typeof EdgeRuntime !== "undefined") { return { "X-Stainless-Lang": "js", "X-Stainless-Package-Version": VERSION, "X-Stainless-OS": "Unknown", "X-Stainless-Arch": `other:${EdgeRuntime}`, "X-Stainless-Runtime": "edge", "X-Stainless-Runtime-Version": process.version }; } if (Object.prototype.toString.call(typeof process !== "undefined" ? process : 0) === "[object process]") { return { "X-Stainless-Lang": "js", "X-Stainless-Package-Version": VERSION, "X-Stainless-OS": normalizePlatform(process.platform), "X-Stainless-Arch": normalizeArch(process.arch), "X-Stainless-Runtime": "node", "X-Stainless-Runtime-Version": process.version }; } const browserInfo = getBrowserInfo(); if (browserInfo) { return { "X-Stainless-Lang": "js", "X-Stainless-Package-Version": VERSION, "X-Stainless-OS": "Unknown", "X-Stainless-Arch": "unknown", "X-Stainless-Runtime": `browser:${browserInfo.browser}`, "X-Stainless-Runtime-Version": browserInfo.version }; } return { "X-Stainless-Lang": "js", "X-Stainless-Package-Version": VERSION, "X-Stainless-OS": "Unknown", "X-Stainless-Arch": "unknown", "X-Stainless-Runtime": "unknown", "X-Stainless-Runtime-Version": "unknown" }; }; function getBrowserInfo() { if (typeof navigator === "undefined" || !navigator) { return null; } const browserPatterns = [ { key: "edge", pattern: /Edge(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ }, { key: "ie", pattern: /MSIE(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ }, { key: "ie", pattern: /Trident(?:.*rv\:(\d+)\.(\d+)(?:\.(\d+))?)?/ }, { key: "chrome", pattern: /Chrome(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ }, { key: "firefox", pattern: /Firefox(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ }, { key: "safari", pattern: /(?:Version\W+(\d+)\.(\d+)(?:\.(\d+))?)?(?:\W+Mobile\S*)?\W+Safari/ } ]; for (const { key, pattern } of browserPatterns) { const match = pattern.exec(navigator.userAgent); if (match) { const major = match[1] || 0; const minor = match[2] || 0; const patch = match[3] || 0; return { browser: key, version: `${major}.${minor}.${patch}` }; } } return null; } var normalizeArch = (arch) => { if (arch === "x32") return "x32"; if (arch === "x86_64" || arch === "x64") return "x64"; if (arch === "arm") return "arm"; if (arch === "aarch64" || arch === "arm64") return "arm64"; if (arch) return `other:${arch}`; return "unknown"; }; var normalizePlatform = (platform) => { platform = platform.toLowerCase(); if (platform.includes("ios")) return "iOS"; if (platform === "android") return "Android"; if (platform === "darwin") return "MacOS"; if (platform === "win32") return "Windows"; if (platform === "freebsd") return "FreeBSD"; if (platform === "openbsd") return "OpenBSD"; if (platform === "linux") return "Linux"; if (platform) return `Other:${platform}`; return "Unknown"; }; var _platformHeaders; var getPlatformHeaders = () => { return _platformHeaders !== null && _platformHeaders !== void 0 ? _platformHeaders : _platformHeaders = getPlatformProperties(); }; var safeJSON = (text) => { try { return JSON.parse(text); } catch (err) { return void 0; } }; var startsWithSchemeRegexp = new RegExp("^(?:[a-z]+:)?//", "i"); var isAbsoluteURL = (url) => { return startsWithSchemeRegexp.test(url); }; var sleep = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms)); var validatePositiveInteger = (name, n) => { if (typeof n !== "number" || !Number.isInteger(n)) { throw new Error(`${name} must be an integer`); } if (n < 0) { throw new Error(`${name} must be a positive integer`); } return n; }; var castToError = (err) => { if (err instanceof Error) return err; return new Error(err); }; var readEnv = (env) => { var _a2, _b, _c, _d; if (typeof process !== "undefined") { return (_b = (_a2 = process.env) === null || _a2 === void 0 ? void 0 : _a2[env]) !== null && _b !== void 0 ? _b : void 0; } if (typeof Deno !== "undefined") { return (_d = (_c = Deno.env) === null || _c === void 0 ? void 0 : _c.get) === null || _d === void 0 ? void 0 : _d.call(_c, env); } return void 0; }; function isEmptyObj(obj) { if (!obj) return true; for (const _k in obj) return false; return true; } function hasOwn(obj, key) { return Object.prototype.hasOwnProperty.call(obj, key); } function debug(action, ...args) { if (typeof process !== "undefined" && process.env["DEBUG"] === "true") { console.log(`OpenAI:DEBUG:${action}`, ...args); } } var uuid4 = () => { return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => { const r = Math.random() * 16 | 0; const v = c === "x" ? r : r & 3 | 8; return v.toString(16); }); }; var isRunningInBrowser = () => { return ( // @ts-ignore typeof window !== "undefined" && // @ts-ignore typeof window.document !== "undefined" && // @ts-ignore typeof navigator !== "undefined" ); }; // node_modules/openai/pagination.mjs var Page = class extends AbstractPage { constructor(client, response, body, options) { super(client, response, body, options); this.object = body.object; this.data = body.data; } getPaginatedItems() { return this.data; } // @deprecated Please use `nextPageInfo()` instead /** * This page represents a response that isn't actually paginated at the API level * so there will never be any next page params. */ nextPageParams() { return null; } nextPageInfo() { return null; } }; var CursorPage = class extends AbstractPage { constructor(client, response, body, options) { super(client, response, body, options); this.data = body.data; } getPaginatedItems() { return this.data; } // @deprecated Please use `nextPageInfo()` instead nextPageParams() { const info = this.nextPageInfo(); if (!info) return null; if ("params" in info) return info.params; const params = Object.fromEntries(info.url.searchParams); if (!Object.keys(params).length) return null; return params; } nextPageInfo() { var _a2, _b; if (!((_a2 = this.data) === null || _a2 === void 0 ? void 0 : _a2.length)) { return null; } const next = (_b = this.data[this.data.length - 1]) === null || _b === void 0 ? void 0 : _b.id; if (!next) return null; return { params: { after: next } }; } }; // node_modules/openai/resource.mjs var APIResource = class { constructor(client) { this.client = client; this.get = client.get.bind(client); this.post = client.post.bind(client); this.patch = client.patch.bind(client); this.put = client.put.bind(client); this.delete = client.delete.bind(client); this.getAPIList = client.getAPIList.bind(client); } }; // node_modules/openai/resources/audio/transcriptions.mjs var Transcriptions = class extends APIResource { /** * Transcribes audio into the input language. */ create(body, options) { return this.post("/audio/transcriptions", multipartFormRequestOptions({ body, ...options })); } }; (function(Transcriptions2) { })(Transcriptions || (Transcriptions = {})); // node_modules/openai/resources/audio/translations.mjs var Translations = class extends APIResource { /** * Translates audio into English. */ create(body, options) { return this.post("/audio/translations", multipartFormRequestOptions({ body, ...options })); } }; (function(Translations2) { })(Translations || (Translations = {})); // node_modules/openai/resources/audio/audio.mjs var Audio = class extends APIResource { constructor() { super(...arguments); this.transcriptions = new Transcriptions(this.client); this.translations = new Translations(this.client); } }; (function(Audio2) { Audio2.Transcriptions = Transcriptions; Audio2.Translations = Translations; })(Audio || (Audio = {})); // node_modules/openai/resources/chat/completions.mjs var Completions = class extends APIResource { create(body, options) { var _a2; return this.post("/chat/completions", { body, ...options, stream: (_a2 = body.stream) !== null && _a2 !== void 0 ? _a2 : false }); } }; (function(Completions3) { })(Completions || (Completions = {})); // node_modules/openai/resources/chat/chat.mjs var Chat = class extends APIResource { constructor() { super(...arguments); this.completions = new Completions(this.client); } }; (function(Chat2) { Chat2.Completions = Completions; })(Chat || (Chat = {})); // node_modules/openai/resources/completions.mjs var Completions2 = class extends APIResource { create(body, options) { var _a2; return this.post("/completions", { body, ...options, stream: (_a2 = body.stream) !== null && _a2 !== void 0 ? _a2 : false }); } }; (function(Completions3) { })(Completions2 || (Completions2 = {})); // node_modules/openai/resources/embeddings.mjs var Embeddings = class extends APIResource { /** * Creates an embedding vector representing the input text. */ create(body, options) { return this.post("/embeddings", { body, ...options }); } }; (function(Embeddings2) { })(Embeddings || (Embeddings = {})); // node_modules/openai/resources/edits.mjs var Edits = class extends APIResource { /** * Creates a new edit for the provided input, instruction, and parameters. * * @deprecated The Edits API is deprecated; please use Chat Completions instead. * * https://openai.com/blog/gpt-4-api-general-availability#deprecation-of-the-edits-api */ create(body, options) { return this.post("/edits", { body, ...options }); } }; (function(Edits2) { })(Edits || (Edits = {})); // node_modules/openai/resources/files.mjs var Files = class extends APIResource { /** * Upload a file that contains document(s) to be used across various * endpoints/features. Currently, the size of all the files uploaded by one * organization can be up to 1 GB. Please contact us if you need to increase the * storage limit. */ create(body, options) { return this.post("/files", multipartFormRequestOptions({ body, ...options })); } /** * Returns information about a specific file. */ retrieve(fileId, options) { return this.get(`/files/${fileId}`, options); } /** * Returns a list of files that belong to the user's organization. */ list(options) { return this.getAPIList("/files", FileObjectsPage, options); } /** * Delete a file. */ del(fileId, options) { return this.delete(`/files/${fileId}`, options); } /** * Returns the contents of the specified file */ retrieveContent(fileId, options) { return this.get(`/files/${fileId}/content`, { ...options, headers: { Accept: "application/json", ...options === null || options === void 0 ? void 0 : options.headers } }); } /** * Waits for the given file to be processed, default timeout is 30 mins. */ async waitForProcessing(id, { pollInterval = 5e3, maxWait = 30 * 60 * 1e3 } = {}) { const TERMINAL_STATES = /* @__PURE__ */ new Set(["processed", "error", "deleted"]); const start = Date.now(); let file = await this.retrieve(id); while (!file.status || !TERMINAL_STATES.has(file.status)) { await sleep(pollInterval); file = await this.retrieve(id); if (Date.now() - start > maxWait) { throw new APIConnectionTimeoutError({ message: `Giving up on waiting for file ${id} to finish processing after ${maxWait} milliseconds.` }); } } return file; } }; var FileObjectsPage = class extends Page { }; (function(Files2) { })(Files || (Files = {})); // node_modules/openai/resources/fine-tunes.mjs var FineTunes = class extends APIResource { /** * Creates a job that fine-tunes a specified model from a given dataset. * * Response includes details of the enqueued job including job status and the name * of the fine-tuned models once complete. * * [Learn more about fine-tuning](/docs/guides/legacy-fine-tuning) */ create(body, options) { return this.post("/fine-tunes", { body, ...options }); } /** * Gets info about the fine-tune job. * * [Learn more about fine-tuning](/docs/guides/legacy-fine-tuning) */ retrieve(fineTuneId, options) { return this.get(`/fine-tunes/${fineTuneId}`, options); } /** * List your organization's fine-tuning jobs */ list(options) { return this.getAPIList("/fine-tunes", FineTunesPage, options); } /** * Immediately cancel a fine-tune job. */ cancel(fineTuneId, options) { return this.post(`/fine-tunes/${fineTuneId}/cancel`, options); } listEvents(fineTuneId, query, options) { var _a2; return this.get(`/fine-tunes/${fineTuneId}/events`, { query, timeout: 864e5, ...options, stream: (_a2 = query === null || query === void 0 ? void 0 : query.stream) !== null && _a2 !== void 0 ? _a2 : false }); } }; var FineTunesPage = class extends Page { }; (function(FineTunes2) { })(FineTunes || (FineTunes = {})); // node_modules/openai/resources/fine-tuning/jobs.mjs var Jobs = class extends APIResource { /** * Creates a job that fine-tunes a specified model from a given dataset. * * Response includes details of the enqueued job including job status and the name * of the fine-tuned models once complete. * * [Learn more about fine-tuning](/docs/guides/fine-tuning) */ create(body, options) { return this.post("/fine_tuning/jobs", { body, ...options }); } /** * Get info about a fine-tuning job. * * [Learn more about fine-tuning](/docs/guides/fine-tuning) */ retrieve(fineTuningJobId, options) { return this.get(`/fine_tuning/jobs/${fineTuningJobId}`, options); } list(query = {}, options) { if (isRequestOptions(query)) { return this.list({}, query); } return this.getAPIList("/fine_tuning/jobs", FineTuningJobsPage, { query, ...options }); } /** * Immediately cancel a fine-tune job. */ cancel(fineTuningJobId, options) { return this.post(`/fine_tuning/jobs/${fineTuningJobId}/cancel`, options); } listEvents(fineTuningJobId, query = {}, options) { if (isRequestOptions(query)) { return this.listEvents(fineTuningJobId, {}, query); } return this.getAPIList(`/fine_tuning/jobs/${fineTuningJobId}/events`, FineTuningJobEventsPage, { query, ...options }); } }; var FineTuningJobsPage = class extends CursorPage { }; var FineTuningJobEventsPage = class extends CursorPage { }; (function(Jobs2) { })(Jobs || (Jobs = {})); // node_modules/openai/resources/fine-tuning/fine-tuning.mjs var FineTuning = class extends APIResource { constructor() { super(...arguments); this.jobs = new Jobs(this.client); } }; (function(FineTuning2) { FineTuning2.Jobs = Jobs; FineTuning2.FineTuningJobsPage = FineTuningJobsPage; FineTuning2.FineTuningJobEventsPage = FineTuningJobEventsPage; })(FineTuning || (FineTuning = {})); // node_modules/openai/resources/images.mjs var Images = class extends APIResource { /** * Creates a variation of a given image. */ createVariation(body, options) { return this.post("/images/variations", multipartFormRequestOptions({ body, ...options })); } /** * Creates an edited or extended image given an original image and a prompt. */ edit(body, options) { return this.post("/images/edits", multipartFormRequestOptions({ body, ...options })); } /** * Creates an image given a prompt. */ generate(body, options) { return this.post("/images/generations", { body, ...options }); } }; (function(Images2) { })(Images || (Images = {})); // node_modules/openai/resources/models.mjs var Models = class extends APIResource { /** * Retrieves a model instance, providing basic information about the model such as * the owner and permissioning. */ retrieve(model, options) { return this.get(`/models/${model}`, options); } /** * Lists the currently available models, and provides basic information about each * one such as the owner and availability. */ list(options) { return this.getAPIList("/models", ModelsPage, options); } /** * Delete a fine-tuned model. You must have the Owner role in your organization to * delete a model. */ del(model, options) { return this.delete(`/models/${model}`, options); } }; var ModelsPage = class extends Page { }; (function(Models2) { })(Models || (Models = {})); // node_modules/openai/resources/moderations.mjs var Moderations = class extends APIResource { /** * Classifies if text violates OpenAI's Content Policy */ create(body, options) { return this.post("/moderations", { body, ...options }); } }; (function(Moderations2) { })(Moderations || (Moderations = {})); // node_modules/openai/index.mjs var _a; var OpenAI = class extends APIClient { /** * API Client for interfacing with the OpenAI API. * * @param {string} [opts.apiKey=process.env['OPENAI_API_KEY']] - The API Key to send to the API. * @param {string} [opts.baseURL] - Override the default base URL for the API. * @param {number} [opts.timeout=10 minutes] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out. * @param {number} [opts.httpAgent] - An HTTP agent used to manage HTTP(s) connections. * @param {Core.Fetch} [opts.fetch] - Specify a custom `fetch` function implementation. * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request. * @param {Core.Headers} opts.defaultHeaders - Default headers to include with every request to the API. * @param {Core.DefaultQuery} opts.defaultQuery - Default query parameters to include with every request to the API. * @param {boolean} [opts.dangerouslyAllowBrowser=false] - By default, client-side use of this library is not allowed, as it risks exposing your secret API credentials to attackers. * @param {string | null} [opts.organization] */ constructor(_b) { var _c, _d, _e; var { apiKey = readEnv("OPENAI_API_KEY"), organization = (_c = readEnv("OPENAI_ORG_ID")) !== null && _c !== void 0 ? _c : null, ...opts } = _b === void 0 ? {} : _b; if (apiKey === void 0) { throw new Error( "The OPENAI_API_KEY environment variable is missing or empty; either provide it, or instantiate the OpenAI client with an apiKey option, like new OpenAI({ apiKey: 'my apiKey' })." ); } const options = { apiKey, organization, ...opts, baseURL: (_d = opts.baseURL) !== null && _d !== void 0 ? _d : `https://api.openai.com/v1` }; if (!options.dangerouslyAllowBrowser && isRunningInBrowser()) { throw new Error( "It looks like you're running in a browser-like environment.\n\nThis is disabled by default, as it risks exposing your secret API credentials to attackers.\nIf you understand the risks and have appropriate mitigations in place,\nyou can set the `dangerouslyAllowBrowser` option to `true`, e.g.,\n\nnew OpenAI({ apiKey, dangerouslyAllowBrowser: true });\n\nhttps://help.openai.com/en/articles/5112595-best-practices-for-api-key-safety\n" ); } super({ baseURL: options.baseURL, timeout: (_e = options.timeout) !== null && _e !== void 0 ? _e : 6e5, httpAgent: options.httpAgent, maxRetries: options.maxRetries, fetch: options.fetch }); this.completions = new Completions2(this); this.chat = new Chat(this); this.edits = new Edits(this); this.embeddings = new Embeddings(this); this.files = new Files(this); this.images = new Images(this); this.audio = new Audio(this); this.moderations = new Moderations(this); this.models = new Models(this); this.fineTuning = new FineTuning(this); this.fineTunes = new FineTunes(this); this._options = options; this.apiKey = apiKey; this.organization = organization; } defaultQuery() { return this._options.defaultQuery; } defaultHeaders(opts) { return { ...super.defaultHeaders(opts), "OpenAI-Organization": this.organization, ...this._options.defaultHeaders }; } authHeaders(opts) { return { Authorization: `Bearer ${this.apiKey}` }; } }; _a = OpenAI; OpenAI.OpenAI = _a; OpenAI.APIError = APIError; OpenAI.APIConnectionError = APIConnectionError; OpenAI.APIConnectionTimeoutError = APIConnectionTimeoutError; OpenAI.APIUserAbortError = APIUserAbortError; OpenAI.NotFoundError = NotFoundError; OpenAI.ConflictError = ConflictError; OpenAI.RateLimitError = RateLimitError; OpenAI.BadRequestError = BadRequestError; OpenAI.AuthenticationError = AuthenticationError; OpenAI.InternalServerError = InternalServerError; OpenAI.PermissionDeniedError = PermissionDeniedError; OpenAI.UnprocessableEntityError = UnprocessableEntityError; var { APIError: APIError2, APIConnectionError: APIConnectionError2, APIConnectionTimeoutError: APIConnectionTimeoutError2, APIUserAbortError: APIUserAbortError2, NotFoundError: NotFoundError2, ConflictError: ConflictError2, RateLimitError: RateLimitError2, BadRequestError: BadRequestError2, AuthenticationError: AuthenticationError2, InternalServerError: InternalServerError2, PermissionDeniedError: PermissionDeniedError2, UnprocessableEntityError: UnprocessableEntityError2 } = error_exports; (function(OpenAI2) { OpenAI2.toFile = toFile; OpenAI2.fileFromPath = fileFromPath; OpenAI2.Page = Page; OpenAI2.CursorPage = CursorPage; OpenAI2.Completions = Completions2; OpenAI2.Chat = Chat; OpenAI2.Edits = Edits; OpenAI2.Embeddings = Embeddings; OpenAI2.Files = Files; OpenAI2.FileObjectsPage = FileObjectsPage; OpenAI2.Images = Images; OpenAI2.Audio = Audio; OpenAI2.Moderations = Moderations; OpenAI2.Models = Models; OpenAI2.ModelsPage = ModelsPage; OpenAI2.FineTuning = FineTuning; OpenAI2.FineTunes = FineTunes; OpenAI2.FineTunesPage = FineTunesPage; })(OpenAI || (OpenAI = {})); var openai_default = OpenAI; // src/components/editor/FetchRenameNoteTitle.ts async function fetchModelRenameTitle(settings, referenceCurrentNoteContent2) { var _a2, _b; const clearYamlContent = referenceCurrentNoteContent2.replace(/---[\s\S]+?---/, "").trim(); const prompt = `You are a title generator. You will give succinct titles that does not contain backslashes, forward slashes, or colons. Only generate a title as your response for: `; try { if (settings.OllamaConnection.RESTAPIURL && settings.OllamaConnection.ollamaModels.includes(settings.general.model)) { try { const ollama = new Ollama2({ host: settings.OllamaConnection.RESTAPIURL }); const response = await ollama.generate({ model: settings.general.model, system: prompt, prompt: clearYamlContent + "\n\n", stream: false, options: { temperature: parseInt(settings.general.temperature), num_predict: 40 } }); let title = response.response; if (title) { title = title.replace(/[\\/:"]/g, ""); } return title; } catch (error) { new import_obsidian5.Notice("Error generating title:", error); console.error("Error generating title:", error); throw error; } } else if (settings.RESTAPIURLConnection.RESTAPIURLModels.includes(settings.general.model)) { try { const response = await (0, import_obsidian5.requestUrl)({ url: settings.RESTAPIURLConnection.RESTAPIURL + "/chat/completions", method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${settings.RESTAPIURLConnection.APIKey}` }, body: JSON.stringify({ model: settings.general.model, messages: [ { role: "system", content: prompt + clearYamlContent }, { role: "user", content: "\n" } ], max_tokens: 40 }) }); let title = response.json.choices[0].message.content; if (title) { title = title.replace(/[\\/:"]/g, ""); } return title; } catch (error) { console.error("Error making API request:", error); throw error; } } else if (ANTHROPIC_MODELS.includes(settings.general.model)) { try { const response = await (0, import_obsidian5.requestUrl)({ url: "https://api.anthropic.com/v1/messages", method: "POST", headers: { "anthropic-version": "2023-06-01", "content-type": "application/json", "x-api-key": settings.APIConnections.anthropic.APIKey }, body: JSON.stringify({ model: settings.general.model, system: prompt, messages: [ { role: "user", content: `${clearYamlContent}` } ], max_tokens: 40, temperature: parseInt(settings.general.temperature) }) }); let title = response.json.content[0].text; if (title) { title = title.replace(/[\\/:"]/g, ""); } return title; } catch (error) { new import_obsidian5.Notice(error); console.error(error); throw error; } } else if (settings.APIConnections.googleGemini.geminiModels.includes(settings.general.model)) { try { const API_KEY = settings.APIConnections.googleGemini.APIKey; const requestBody = { contents: [{ parts: [ { text: prompt + clearYamlContent } ] }] }; const response = await (0, import_obsidian5.requestUrl)({ url: `https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent?key=${API_KEY}`, method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(requestBody) }); let title = response.json.candidates[0].content.parts[0].text; if (title) { title = title.replace(/[\\/:"]/g, ""); } return title; } catch (error) { console.error(error); } } else if (settings.APIConnections.mistral.mistralModels.includes(settings.general.model)) { try { const response = await (0, import_obsidian5.requestUrl)({ url: "https://api.mistral.ai/v1/chat/completions", method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${settings.APIConnections.mistral.APIKey}` }, body: JSON.stringify({ model: settings.general.model, messages: [ { role: "system", content: prompt + clearYamlContent }, { role: "user", content: "\n" } ], max_tokens: 40 }) }); let title = response.json.choices[0].message.content; if (title) { title = title.replace(/[\\/:"]/g, ""); } return title; } catch (error) { console.error(error); } } else if (OPENAI_MODELS.includes(settings.general.model) || settings.APIConnections.openAI.openAIBaseModels.includes(settings.general.model)) { const openai = new openai_default({ apiKey: settings.APIConnections.openAI.APIKey, baseURL: settings.APIConnections.openAI.openAIBaseUrl, dangerouslyAllowBrowser: true // apiKey is stored within data.json }); const chatCompletion = await openai.chat.completions.create({ model: settings.general.model, max_tokens: 40, messages: [ { role: "system", content: prompt + clearYamlContent }, { role: "user", content: "" } ] }); let title = chatCompletion.choices[0].message.content; if (title) { title = title.replace(/[\\/:"]/g, ""); } return title; } else if (settings.APIConnections.openRouter.openRouterModels.includes(settings.general.model)) { try { const response = await (0, import_obsidian5.requestUrl)({ url: "https://openrouter.ai/api/v1/chat/completions", method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${settings.APIConnections.openRouter.APIKey}` }, body: JSON.stringify({ model: settings.general.model, messages: [ { role: "system", content: prompt + clearYamlContent }, { role: "user", content: "\n" } ], max_tokens: 40 }) }); let title = response.json.choices[0].message.content; if (title) { title = title.replace(/[\\/:"]/g, ""); } return title; } catch (error) { console.error("Error making API request:", error); throw error; } } else { throw new Error("Invalid model selected for renaming note title. Please check your settings."); } } catch (error) { console.log("ERROR"); throw new Error(((_b = (_a2 = error.response) == null ? void 0 : _a2.data) == null ? void 0 : _b.error) || error.message); } } // src/components/chat/Commands.ts var lastLoadedChatHistoryFile = null; var commandMap = { "/help": (input, settings, plugin) => commandHelp(plugin, settings), "/model": (input, settings, plugin) => commandModel(input, settings, plugin), "/profile": (input, settings, plugin) => commandProfile(input, settings, plugin), "/prompt": (input, settings, plugin) => commandPrompt(input, settings, plugin), "/reference": (input, settings, plugin) => commandReference(input, settings, plugin), "/temperature": (input, settings, plugin) => commandTemperature(input, settings, plugin), "/maxtokens": (input, settings, plugin) => commandMaxTokens(input, settings, plugin), "/append": (input, settings, plugin) => commandAppend(plugin, settings), "/save": (input, settings, plugin) => commandSave(plugin, settings), "/load": (input, settings, plugin) => commandLoad(input, plugin, settings), "/clear": (input, settings, plugin) => removeMessageThread(plugin, 0), "/stop": (input, settings, plugin) => commandStop() }; var aliases = { "/help": ["/h", "/man", "/manual", "/commands"], "/model": ["/m", "/models"], "/profile": ["/p", "/prof", "/profiles"], "/prompt": ["/prompts"], "/reference": ["/ref"], "/temperature": ["/temp", ""], "/clear": ["/c"], "/stop": ["/s"] }; Object.entries(aliases).forEach(([command, aliasList]) => { aliasList.forEach((alias) => commandMap[alias] = commandMap[command]); }); function executeCommand(input, settings, plugin) { const command = input.split(" ")[0]; const handler = commandMap[command] || (() => commandFalse()); return handler(input, settings, plugin); } async function commandFalse() { new import_obsidian6.Notice("Command not recognized. Type `/help` for commands."); const chatbox = document.querySelector(".chatbox textarea"); chatbox.value = ""; } function commandHelp(plugin, settings) { const messageContainer = document.querySelector("#messageContainer"); const botMessageDiv = document.createElement("div"); botMessageDiv.className = "botMessage"; botMessageDiv.style.backgroundColor = colorToHex(settings.appearance.botMessageBackgroundColor || getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.botMessageBackgroundColor).trim()); const botMessageToolBarDiv = document.createElement("div"); botMessageToolBarDiv.className = "botMessageToolBar"; const botNameSpan = document.createElement("span"); botNameSpan.textContent = settings.appearance.chatbotName || DEFAULT_SETTINGS.appearance.chatbotName; botNameSpan.className = "chatbotName"; const messageBlockDiv = document.createElement("div"); messageBlockDiv.className = "messageBlock"; const displayCommandBotMessageDiv = document.createElement("div"); displayCommandBotMessageDiv.className = "commandBotMessage"; const header = document.createElement("h3"); header.textContent = "Manual"; header.style.textAlign = "center"; displayCommandBotMessageDiv.appendChild(header); const generalCommandHeader = document.createElement("h4"); generalCommandHeader.textContent = "General Commands"; generalCommandHeader.style.textAlign = "left"; displayCommandBotMessageDiv.appendChild(generalCommandHeader); const commandClearP = document.createElement("p"); commandClearP.innerHTML = "/clear or /c - Clear chat history."; displayCommandBotMessageDiv.appendChild(commandClearP); const commandRefOnP = document.createElement("p"); commandRefOnP.innerHTML = '/ref on - Turn on "reference current note".'; displayCommandBotMessageDiv.appendChild(commandRefOnP); const commandRefOffP = document.createElement("p"); commandRefOffP.innerHTML = '/ref off - Turn off "reference current note".'; displayCommandBotMessageDiv.appendChild(commandRefOffP); const commandMaxTokensP = document.createElement("p"); commandMaxTokensP.innerHTML = "/maxtokens [VALUE] - Set max tokens."; displayCommandBotMessageDiv.appendChild(commandMaxTokensP); const commandTempP = document.createElement("p"); commandTempP.innerHTML = "/temp [VALUE] - Change temperature range from 0 to 2."; displayCommandBotMessageDiv.appendChild(commandTempP); const profileCommandHeader = document.createElement("h4"); profileCommandHeader.textContent = "Profile Commands"; profileCommandHeader.style.textAlign = "left"; displayCommandBotMessageDiv.appendChild(profileCommandHeader); const commandProfileListP = document.createElement("p"); commandProfileListP.innerHTML = "/profile - List profile."; displayCommandBotMessageDiv.appendChild(commandProfileListP); const commandProfileChangeP = document.createElement("p"); commandProfileChangeP.innerHTML = "/profile [PROFILE-NAME] or [VALUE] - Change profile."; displayCommandBotMessageDiv.appendChild(commandProfileChangeP); const modelCommandHeader = document.createElement("h4"); modelCommandHeader.textContent = "Model Commands"; modelCommandHeader.style.textAlign = "left"; displayCommandBotMessageDiv.appendChild(modelCommandHeader); const commandModelListP = document.createElement("p"); commandModelListP.innerHTML = "/model - List model."; displayCommandBotMessageDiv.appendChild(commandModelListP); const commandModelChangeP = document.createElement("p"); commandModelChangeP.innerHTML = "/model [MODEL-NAME] or [VALUE] - Change model."; displayCommandBotMessageDiv.appendChild(commandModelChangeP); const promptCommandHeader = document.createElement("h4"); promptCommandHeader.textContent = "Prompt Commands"; promptCommandHeader.style.textAlign = "left"; displayCommandBotMessageDiv.appendChild(promptCommandHeader); const commandPromptListP = document.createElement("p"); commandPromptListP.innerHTML = "/prompt - List prompts."; displayCommandBotMessageDiv.appendChild(commandPromptListP); const commandPromptChangeP = document.createElement("p"); commandPromptChangeP.innerHTML = "/prompt [PROMPT-NAME] or [VALUE] - Change prompts."; displayCommandBotMessageDiv.appendChild(commandPromptChangeP); const commandPromptClearP = document.createElement("p"); commandPromptClearP.innerHTML = "/prompt clear - Clear prompt."; displayCommandBotMessageDiv.appendChild(commandPromptClearP); const editorCommandHeader = document.createElement("h4"); editorCommandHeader.textContent = "Editor Commands"; editorCommandHeader.style.textAlign = "left"; displayCommandBotMessageDiv.appendChild(editorCommandHeader); const commandAppendP = document.createElement("p"); commandAppendP.innerHTML = "/append - Append current chat history to current active note."; displayCommandBotMessageDiv.appendChild(commandAppendP); const commandSaveP = document.createElement("p"); commandSaveP.innerHTML = "/save - Save current chat history to a note."; displayCommandBotMessageDiv.appendChild(commandSaveP); const commandLoadP = document.createElement("p"); commandLoadP.innerHTML = "/load - List or load a chat history into view."; displayCommandBotMessageDiv.appendChild(commandLoadP); const streamCommandHeader = document.createElement("h4"); streamCommandHeader.textContent = "Response Commands"; streamCommandHeader.style.textAlign = "left"; displayCommandBotMessageDiv.appendChild(streamCommandHeader); const commandStopP = document.createElement("p"); commandStopP.innerHTML = "/stop or /s - Stop fetching response. Warning: Anthropric models cannot be aborted. Please use with caution."; displayCommandBotMessageDiv.appendChild(commandStopP); messageBlockDiv.appendChild(displayCommandBotMessageDiv); botMessageToolBarDiv.appendChild(botNameSpan); botMessageDiv.appendChild(botMessageToolBarDiv); botMessageDiv.appendChild(messageBlockDiv); const index2 = messageHistory.length - 1; addMessage(plugin, messageBlockDiv.innerHTML, "botMessage", settings, index2); messageContainer.appendChild(botMessageDiv); } async function commandModel(input, settings, plugin) { const messageContainer = document.querySelector("#messageContainer"); const ollamaModels = settings.OllamaConnection.ollamaModels.map((model) => model); const RESTAPIModels = settings.RESTAPIURLConnection.RESTAPIURLModels.map((model) => model); const anthropicModels = settings.APIConnections.anthropic.anthropicModels.map((model) => model); const googleGeminiModels = settings.APIConnections.googleGemini.geminiModels.map((model) => model); const mistralModels = settings.APIConnections.mistral.mistralModels.map((model) => model); const openAIBaseModels = settings.APIConnections.openAI.openAIBaseModels.map((model) => model); const openRouterModels = settings.APIConnections.openRouter.openRouterModels.map((model) => model); const allModels = [ ...settings.OllamaConnection.ollamaModels, ...settings.RESTAPIURLConnection.RESTAPIURLModels, ...settings.APIConnections.anthropic.anthropicModels, ...settings.APIConnections.googleGemini.geminiModels, ...settings.APIConnections.mistral.mistralModels, ...settings.APIConnections.openAI.openAIBaseModels, ...settings.APIConnections.openRouter.openRouterModels ]; if (!input.split(" ")[1]) { let currentModel = settings.general.model; if (!currentModel) { currentModel = "Empty"; } const botMessageDiv = document.createElement("div"); botMessageDiv.className = "botMessage"; botMessageDiv.style.backgroundColor = colorToHex(settings.appearance.botMessageBackgroundColor || getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.botMessageBackgroundColor).trim()); const botMessageToolBarDiv = document.createElement("div"); botMessageToolBarDiv.className = "botMessageToolBar"; const botNameSpan = document.createElement("span"); botNameSpan.textContent = settings.appearance.chatbotName || DEFAULT_SETTINGS.appearance.chatbotName; botNameSpan.className = "chatbotName"; const messageBlockDiv = document.createElement("div"); messageBlockDiv.className = "messageBlock"; const displayCommandBotMessageDiv = document.createElement("div"); displayCommandBotMessageDiv.className = "commandBotMessage"; const header = document.createElement("h3"); header.textContent = "Model List"; header.style.textAlign = "center"; displayCommandBotMessageDiv.appendChild(header); const currentModelP = document.createElement("p"); currentModelP.innerHTML = `Current Model: ${currentModel}`; currentModelP.style.textAlign = "center"; displayCommandBotMessageDiv.appendChild(currentModelP); const apiLists = [ { header: "Ollama Models", items: ollamaModels }, { header: "REST API Models", items: RESTAPIModels }, { header: "Anthropic Models", items: anthropicModels }, { header: "Google Gemini Models", items: googleGeminiModels }, { header: "Mistral Models", items: mistralModels }, { header: "OpenAI-Based Models", items: openAIBaseModels }, { header: "OpenRouter Models", items: openRouterModels } ]; let currentStartIndex = 1; apiLists.forEach((api) => { if (Array.isArray(api.items) && api.items.length) { const header2 = document.createElement("h4"); header2.textContent = api.header; displayCommandBotMessageDiv.appendChild(header2); const list = document.createElement("ol"); list.setAttribute("start", String(currentStartIndex)); api.items.forEach((item) => { const listItem = document.createElement("li"); listItem.textContent = item; list.appendChild(listItem); }); displayCommandBotMessageDiv.appendChild(list); currentStartIndex += api.items.length; } }); messageBlockDiv.appendChild(displayCommandBotMessageDiv); botMessageToolBarDiv.appendChild(botNameSpan); botMessageDiv.appendChild(botMessageToolBarDiv); botMessageDiv.appendChild(messageBlockDiv); const index2 = messageHistory.length - 1; addMessage(plugin, messageBlockDiv.innerHTML, "botMessage", settings, index2); messageContainer.appendChild(botMessageDiv); } if (input.split(" ")[1] !== void 0) { const inputModel = input.split(" ")[1].replace(/^"(.*)"$/, "$1"); const modelAliases = {}; for (let i = 1; i <= allModels.length; i++) { const model = allModels[i - 1]; modelAliases[i] = model; } if (Object.entries(modelAliases).find(([key, val]) => key === inputModel)) { settings.general.model = modelAliases[inputModel]; new import_obsidian6.Notice(`Updated model to ${settings.general.model}`); } else if (Object.entries(modelAliases).find(([key, val]) => val === inputModel)) { settings.general.model = modelAliases[Object.keys(modelAliases).find((key) => modelAliases[key] === inputModel) || ""]; new import_obsidian6.Notice(`Updated model to ${settings.general.model}`); } else { new import_obsidian6.Notice("Invalid model."); } await plugin.saveSettings(); } } async function commandProfile(input, settings, plugin) { const messageContainer = document.querySelector("#messageContainer"); if (!settings.profiles.profileFolderPath) { new import_obsidian6.Notice("Profile folder path not set."); const commandBotMessage = "

Profile folder path not set.

"; const botMessageDiv = displayCommandBotMessage(plugin, settings, messageHistory, commandBotMessage); messageContainer.appendChild(botMessageDiv); return; } const files = plugin.app.vault.getFiles().filter((file) => file.path.startsWith(plugin.settings.profiles.profileFolderPath)); files.sort((a, b) => a.name.localeCompare(b.name)); let currentProfile = settings.profiles.profile.replace(/\.[^/.]+$/, ""); if (!input.split(" ")[1]) { const fileListItems = files.map((file) => { const fileNameWithoutExtension = file.name.replace(/\.[^/.]+$/, ""); return `
  • ${fileNameWithoutExtension}
  • `; }).join(""); if (!currentProfile) { currentProfile = "Empty"; } const commandBotMessage = `

    Profiles

    Current profile: ${currentProfile}

      ${fileListItems}
    `; const botMessageDiv = displayCommandBotMessage(plugin, settings, messageHistory, commandBotMessage); messageContainer.appendChild(botMessageDiv); return; } if (input.startsWith("/p") || input.startsWith("/prof") || input.startsWith("/profile") || input.startsWith("/profiles")) { let inputValue = input.split(" ").slice(1).join(" ").trim(); if (inputValue.startsWith('"') && inputValue.endsWith('"') || inputValue.startsWith("'") && inputValue.endsWith("'")) { inputValue = inputValue.substring(1, inputValue.length - 1); } const profileAliases = {}; for (let i = 1; i <= files.length; i++) { const fileNameWithoutExtension = files[i - 1].name.replace(/\.[^/.]+$/, ""); profileAliases[i.toString().toLowerCase()] = fileNameWithoutExtension; } if (profileAliases[inputValue]) { plugin.settings.profiles.profile = profileAliases[inputValue] + ".md"; const profileFilePath = plugin.settings.profiles.profileFolderPath + "/" + profileAliases[inputValue] + ".md"; const currentProfile2 = plugin.app.vault.getAbstractFileByPath(profileFilePath); const currentProfileName = settings.profiles.profile.replace(/\.[^/.]+$/, ""); const profileIndex = files.findIndex((file) => file.basename === currentProfileName); settings.profiles.lastLoadedChatHistoryPath = settings.profiles.lastLoadedChatHistory[profileIndex]; plugin.activateView(); await updateSettingsFromFrontMatter(plugin, currentProfile2); await plugin.saveSettings(); } else if (Object.values(profileAliases).map((v) => v.toLowerCase()).includes(inputValue.toLowerCase())) { const matchedProfile = Object.entries(profileAliases).find(([key, value]) => value.toLowerCase() === inputValue.toLowerCase()); if (matchedProfile) { plugin.settings.profiles.profile = matchedProfile[1] + ".md"; const profileFilePath = plugin.settings.profiles.profileFolderPath + "/" + matchedProfile[1] + ".md"; const currentProfile2 = plugin.app.vault.getAbstractFileByPath(profileFilePath); const currentProfileName = settings.profiles.profile.replace(/\.[^/.]+$/, ""); const profileIndex = files.findIndex((file) => file.basename === currentProfileName); settings.profiles.lastLoadedChatHistoryPath = settings.profiles.lastLoadedChatHistory[profileIndex]; plugin.activateView(); await updateSettingsFromFrontMatter(plugin, currentProfile2); await plugin.saveSettings(); } } else { new import_obsidian6.Notice("Invalid profile."); } await plugin.saveSettings(); } } async function commandPrompt(input, settings, plugin) { const messageContainer = document.querySelector("#messageContainer"); if (!settings.prompts.promptFolderPath) { new import_obsidian6.Notice("Prompt folder path not set."); const commandBotMessage = "

    Prompt folder path not set.

    "; const botMessageDiv = displayCommandBotMessage(plugin, settings, messageHistory, commandBotMessage); messageContainer.appendChild(botMessageDiv); return; } const files = plugin.app.vault.getFiles().filter((file) => file.path.startsWith(plugin.settings.prompts.promptFolderPath)); files.sort((a, b) => a.name.localeCompare(b.name)); if (!input.split(" ")[1]) { const fileListItems = files.map((file) => { const fileNameWithoutExtension = file.name.replace(/\.[^/.]+$/, ""); return `
  • ${fileNameWithoutExtension}
  • `; }).join(""); let currentPrompt = settings.prompts.prompt; if (!currentPrompt) { currentPrompt = "Empty"; } const commandBotMessage = `

    Prompts

    Current prompt: ${currentPrompt.replace(".md", "")}

      ${fileListItems}
    `; const botMessageDiv = displayCommandBotMessage(plugin, settings, messageHistory, commandBotMessage); messageContainer.appendChild(botMessageDiv); return; } if (input.startsWith("/prompt")) { let inputValue = input.split(" ").slice(1).join(" ").trim(); if (inputValue.startsWith('"') && inputValue.endsWith('"') || inputValue.startsWith("'") && inputValue.endsWith("'")) { inputValue = inputValue.substring(1, inputValue.length - 1); } if (inputValue === "clear" || inputValue === "c") { settings.prompts.prompt = ""; new import_obsidian6.Notice("Prompt cleared."); await plugin.saveSettings(); } const promptAliases = {}; for (let i = 1; i <= files.length; i++) { const fileNameWithoutExtension = files[i - 1].name.replace(/\.[^/.]+$/, ""); promptAliases[i.toString()] = fileNameWithoutExtension; } let currentModel; if (promptAliases[inputValue]) { settings.prompts.prompt = promptAliases[inputValue] + ".md"; currentModel = settings.prompts.prompt.replace(/\.[^/.]+$/, ""); new import_obsidian6.Notice(`Prompt updated to '${currentModel}'`); } else if (Object.values(promptAliases).map((v) => v.toLowerCase()).includes(inputValue.toLowerCase())) { const matchedProfile = Object.entries(promptAliases).find(([key, value]) => value.toLowerCase() === inputValue.toLowerCase()); if (matchedProfile) { settings.prompts.prompt = matchedProfile[1] + ".md"; currentModel = settings.prompts.prompt.replace(/\.[^/.]+$/, ""); new import_obsidian6.Notice(`Prompt updated to '${currentModel}'`); } } else { if (inputValue !== "clear" && inputValue !== "c") { new import_obsidian6.Notice("Invalid prompt."); } } await plugin.saveSettings(); } } async function commandReference(input, settings, plugin) { var _a2; const referenceCurrentNoteElement = document.getElementById("referenceCurrentNote"); const inputValue = (_a2 = input.split(" ")[1]) == null ? void 0 : _a2.toLowerCase(); if (inputValue === "true" || inputValue === "on") { settings.general.enableReferenceCurrentNote = true; if (referenceCurrentNoteElement) { referenceCurrentNoteElement.style.display = "block"; } new import_obsidian6.Notice("Reference current note: on."); } else if (inputValue === "false" || inputValue === "off") { settings.general.enableReferenceCurrentNote = false; if (referenceCurrentNoteElement) { referenceCurrentNoteElement.style.display = "none"; } new import_obsidian6.Notice("Reference current note: off."); } else { new import_obsidian6.Notice("Type `/ref on` or `/ref off` to turn on/off reference current note."); } await plugin.saveSettings(); } async function commandTemperature(input, settings, plugin) { const inputValue = input.split(" ")[1]; const floatValue = parseFloat(inputValue); if (settings && !isNaN(floatValue)) { if (floatValue < 0) { settings.general.temperature = "0.00"; } else if (floatValue > 2) { settings.general.temperature = "2.00"; } else { settings.general.temperature = floatValue.toFixed(2); } new import_obsidian6.Notice(`Temperature updated: ${settings.general.temperature}`); } else { new import_obsidian6.Notice(`Current temperature: ${settings.general.temperature}`); } await plugin.saveSettings(); } async function commandMaxTokens(input, settings, plugin) { const commandParts = input.split(" "); const commandAction = commandParts[1] ? commandParts[1].toLowerCase() : ""; if (commandAction === "c" || commandAction === "clear") { settings.general.max_tokens = ""; new import_obsidian6.Notice("Max tokens cleared."); } else if (commandAction !== "") { const inputValue = parseInt(commandAction); if (!isNaN(inputValue) && inputValue >= 0) { settings.general.max_tokens = inputValue.toString(); new import_obsidian6.Notice(`Max tokens updated: ${inputValue}`); } else { new import_obsidian6.Notice("Max tokens update: invalid"); } } else { if (settings.general.max_tokens === "") { new import_obsidian6.Notice("Current max tokens: Empty"); } else { new import_obsidian6.Notice(`Current max tokens: ${settings.general.max_tokens}`); } } await plugin.saveSettings(); } async function commandAppend(plugin, settings) { let markdownContent = ""; const activeFile = plugin.app.workspace.getActiveFile(); if ((activeFile == null ? void 0 : activeFile.extension) === "md") { const existingContent = await plugin.app.vault.read(activeFile); const userNames = document.querySelectorAll(".userName"); let userNameText = "USER"; if (userNames.length > 0) { const userNameNode = userNames[0]; Array.from(userNameNode.childNodes).forEach((node) => { if (node.nodeType === Node.TEXT_NODE && node.textContent) { userNameText = node.textContent.trim().toUpperCase(); } }); } const chatbotNames = document.querySelectorAll(".chatbotName"); const chatbotNameText = chatbotNames.length > 0 && chatbotNames[0].textContent ? chatbotNames[0].textContent.toUpperCase() : "ASSISTANT"; if (await this.app.vault.adapter.exists(fileNameMessageHistoryJson(plugin))) { try { const jsonContent = await this.app.vault.adapter.read(fileNameMessageHistoryJson(plugin)); const messages = JSON.parse(jsonContent); let skipNext = false; markdownContent += messages.filter((messageHistory2, index2, array) => { if (skipNext && messageHistory2.role === "assistant") { skipNext = false; return false; } if (messageHistory2.content.startsWith("/") || messageHistory2.content.includes("errorBotMessage")) { skipNext = index2 + 1 < array.length && array[index2 + 1].role === "assistant" || messageHistory2.role === "assistant"; return false; } return true; }).map((message) => { let roleText = message.role.toUpperCase(); roleText = roleText === "USER" ? userNameText : roleText; roleText = roleText === "ASSISTANT" ? chatbotNameText : roleText; return `###### ${roleText} ${message.content} `; }).join("\n"); } catch (error) { const messageContainer = document.querySelector("#messageContainer"); const botMessageDiv = displayCommandBotMessage(plugin, settings, messageHistory, error); messageContainer.appendChild(botMessageDiv); console.error("Error processing message history:", error); } } const updatedContent = existingContent + "\n" + markdownContent; await plugin.app.vault.modify(activeFile, updatedContent); new import_obsidian6.Notice("Appended conversation."); } else { new import_obsidian6.Notice("No active Markdown file detected."); } } async function commandSave(plugin, settings) { new import_obsidian6.Notice("Saving conversation..."); let folderName = settings.chatHistory.chatHistoryPath; if (!await plugin.app.vault.adapter.exists(folderName)) { await plugin.app.vault.createFolder(folderName); } const baseFileName = "Chat History"; const fileExtension = ".md"; if (folderName && !folderName.endsWith("/")) { folderName += "/"; } const now = new Date(); const dateTimeStamp = now.getFullYear() + "-" + (now.getMonth() + 1).toString().padStart(2, "0") + "-" + now.getDate().toString().padStart(2, "0") + " " + now.getHours().toString().padStart(2, "0") + "-" + now.getMinutes().toString().padStart(2, "0") + "-" + now.getSeconds().toString().padStart(2, "0"); try { let markdownContent = ""; const allFiles = plugin.app.vault.getFiles(); const templateFile = allFiles.find((file) => file.path.toLowerCase() === settings.chatHistory.templateFilePath.toLowerCase()); if (templateFile) { let fileContent = await plugin.app.vault.read(templateFile); if (/^---\s*[\s\S]*?---/.test(fileContent)) { if (!/^model:\s/m.test(fileContent)) { fileContent = fileContent.replace(/^---/, `--- model: ${settings.general.model}`); } } else { fileContent = `--- model: ${settings.general.model} --- ` + fileContent; } markdownContent += fileContent; } else { markdownContent += `--- model: ${settings.general.model} --- `; } const userNames = document.querySelectorAll(".userName"); let userNameText = "USER"; if (userNames.length > 0) { const userNameNode = userNames[0]; Array.from(userNameNode.childNodes).forEach((node) => { if (node.nodeType === Node.TEXT_NODE && node.textContent) { userNameText = node.textContent.trim().toUpperCase(); } }); } const chatbotNames = document.querySelectorAll(".chatbotName"); const chatbotNameText = chatbotNames.length > 0 && chatbotNames[0].textContent ? chatbotNames[0].textContent.toUpperCase() : "ASSISTANT"; if (await plugin.app.vault.adapter.exists(fileNameMessageHistoryJson(plugin))) { try { const jsonContent = await plugin.app.vault.adapter.read(fileNameMessageHistoryJson(plugin)); const messages = JSON.parse(jsonContent); let skipNext = false; markdownContent += messages.filter((messageHistory2, index2, array) => { if (skipNext && messageHistory2.role === "assistant") { skipNext = false; return false; } if (messageHistory2.content.startsWith("/") || messageHistory2.content.includes("errorBotMessage")) { skipNext = index2 + 1 < array.length && array[index2 + 1].role === "assistant" || messageHistory2.role === "assistant"; return false; } return true; }).map((message) => { let roleText = message.role.toUpperCase(); roleText = roleText === "USER" ? userNameText : roleText; roleText = roleText === "ASSISTANT" ? chatbotNameText : roleText; const regexRenderedBlock = /[\s\S]*?<\/block-rendered>/g; message.content = message.content.replace(regexRenderedBlock, "").trim(); const regexRenderedNote = /[\s\S]*?<\/note-rendered>/g; message.content = message.content.replace(regexRenderedNote, "").trim(); return `###### ${roleText} ${message.content} `; }).join("\n"); } catch (error) { console.error("Error processing message history:", error); } } let fileName = ""; if (settings.chatHistory.allowRenameNoteTitle) { let uniqueNameFound = false; let modelRenameTitle; const fileNameExists = (name) => { return allFiles.some((file) => file.path === folderName + name + fileExtension); }; while (!uniqueNameFound) { modelRenameTitle = await fetchModelRenameTitle(settings, markdownContent); if (!fileNameExists(modelRenameTitle)) { uniqueNameFound = true; } } fileName = folderName + modelRenameTitle + fileExtension; } else { fileName = folderName + baseFileName + " " + dateTimeStamp + fileExtension; } if (settings.profiles.lastLoadedChatHistoryPath !== null) { lastLoadedChatHistoryFile = plugin.app.vault.getAbstractFileByPath(settings.profiles.lastLoadedChatHistoryPath); } if (lastLoadedChatHistoryFile === null) { const file = await plugin.app.vault.create(fileName, markdownContent); const profileFiles = plugin.app.vault.getFiles().filter((file2) => file2.path.startsWith(settings.profiles.profileFolderPath)); profileFiles.sort((a, b) => a.name.localeCompare(b.name)); const currentProfile = settings.profiles.profile.replace(/\.[^/.]+$/, ""); const profileIndex = profileFiles.findIndex((file2) => file2.basename === currentProfile); if (file) { settings.profiles.lastLoadedChatHistoryPath = file.path; settings.profiles.lastLoadedChatHistory[profileIndex] = file.path; plugin.app.workspace.openLinkText(fileName, "", true, { active: true }); } } else { await plugin.app.vault.modify(lastLoadedChatHistoryFile, markdownContent); const activeFile = plugin.app.workspace.getActiveFile(); if ((activeFile == null ? void 0 : activeFile.path) !== lastLoadedChatHistoryFile.path) { plugin.app.workspace.openLinkText(lastLoadedChatHistoryFile.path, lastLoadedChatHistoryFile.path, true, { active: true }); } } new import_obsidian6.Notice(`Saved to '${lastLoadedChatHistoryFile == null ? void 0 : lastLoadedChatHistoryFile.name}'`); await plugin.saveSettings(); } catch (error) { console.error("Failed to create note:", error); } } async function commandLoad(input, plugin, settings) { const messageContainer = document.querySelector("#messageContainer"); const folderPath = plugin.settings.chatHistory.chatHistoryPath.trim() || DEFAULT_SETTINGS.chatHistory.chatHistoryPath; const files = plugin.app.vault.getFiles().filter((file) => file.path.startsWith(folderPath)); files.sort((a, b) => a.name.localeCompare(b.name)); const profileFiles = plugin.app.vault.getFiles().filter((file) => file.path.startsWith(plugin.settings.profiles.profileFolderPath)); profileFiles.sort((a, b) => a.name.localeCompare(b.name)); const currentProfile = settings.profiles.profile.replace(/\.[^/.]+$/, ""); const profileIndex = profileFiles.findIndex((file) => file.basename === currentProfile); if (!input.split(" ")[1]) { const fileGroups = files.reduce((acc, file) => { const fileNameWithoutExtension = file.name.replace(/\.[^/.]+$/, ""); if (acc[fileNameWithoutExtension]) { acc[fileNameWithoutExtension].count++; } else { acc[fileNameWithoutExtension] = { count: 1 }; } return acc; }, {}); const fileListItems = Object.entries(fileGroups).map(([fileName, { count }]) => { return count > 1 ? `
  • ${fileName} [${count} files found]
  • ` : `
  • ${fileName}
  • `; }).join(""); const commandBotMessage = `

    Chat History

    Current Chat History: ${settings.profiles.lastLoadedChatHistory[profileIndex] ? settings.profiles.lastLoadedChatHistory[profileIndex] : "Empty"}

      ${fileListItems}
    `; const botMessageDiv = displayCommandBotMessage(plugin, settings, messageHistory, commandBotMessage); messageContainer.appendChild(botMessageDiv); return; } if (input.startsWith("/load")) { let inputValue = input.split(" ").slice(1).join(" ").trim(); if (inputValue.startsWith('"') && inputValue.endsWith('"') || inputValue.startsWith("'") && inputValue.endsWith("'")) { inputValue = inputValue.substring(1, inputValue.length - 1); } const loadAliases = {}; let currentIndex = 1; for (let i = 0; i < files.length; i++) { const fileNameWithoutExtension = files[i].name.replace(/\.[^/.]+$/, ""); const existingKey = Object.values(loadAliases).find( (value) => value === fileNameWithoutExtension ); if (!existingKey) { loadAliases[currentIndex.toString().toLowerCase()] = fileNameWithoutExtension; currentIndex++; } } const messageHistory2 = []; const loadChatHistory = async (filePath) => { const currentLoad = plugin.app.vault.getAbstractFileByPath(filePath); const fileContent = await plugin.app.vault.cachedRead(currentLoad); const contentWithoutFrontmatter = fileContent.replace(/^---\n[\s\S]*?\n---\n/, ""); const lines = contentWithoutFrontmatter.split("\n"); let currentRole = ""; let currentContent = ""; let headerCount = 0; for (const line of lines) { if (line.startsWith("###### ")) { headerCount++; if (currentContent) { messageHistory2.push({ role: currentRole, content: currentContent.trim() }); } currentRole = currentRole === "user" ? "assistant" : "user"; currentContent = ""; } else { currentContent += line + "\n"; } } if (currentContent) { messageHistory2.push({ role: currentRole, content: currentContent.trim() }); } if (headerCount % 2 !== 0) { new import_obsidian6.Notice("Incorrect formatting."); return false; } const updatedJsonString = JSON.stringify(messageHistory2, null, 4); await plugin.app.vault.adapter.write(fileNameMessageHistoryJson(plugin), updatedJsonString); plugin.activateView(); return true; }; if (loadAliases[inputValue]) { const matchingFiles = files.filter((file) => file.name.includes(loadAliases[inputValue])); const modal = new import_obsidian6.Modal(plugin.app); const modalContent = document.createElement("div"); modalContent.classList.add("modal-content"); const heading = document.createElement("h2"); heading.textContent = "Load Chat History"; modalContent.appendChild(heading); if (matchingFiles.length === 1) { const message = document.createElement("p"); message.textContent = `Are you sure you want to override your current chat history with "${matchingFiles[0].name}"?`; modalContent.appendChild(message); const confirmLoadButton = document.createElement("button"); confirmLoadButton.id = "confirmLoad"; confirmLoadButton.textContent = "Confirm"; modalContent.appendChild(confirmLoadButton); confirmLoadButton == null ? void 0 : confirmLoadButton.addEventListener("click", async function() { const selectedFile = matchingFiles[0]; const chatHistoryFilePath = selectedFile.path; const success = await loadChatHistory(chatHistoryFilePath); if (success) { new import_obsidian6.Notice(`Switched to '${selectedFile.path}' chat history.`); lastLoadedChatHistoryFile = selectedFile; settings.profiles.lastLoadedChatHistoryPath = selectedFile.path; settings.profiles.lastLoadedChatHistory[profileIndex] = settings.profiles.lastLoadedChatHistoryPath; await plugin.saveSettings(); } modal.close(); }); } else { const message = document.createElement("p"); message.textContent = "Select a chat history to override:"; modalContent.appendChild(message); const optionsContainer = document.createElement("div"); optionsContainer.classList.add("file-options"); optionsContainer.style.marginBottom = "16px"; matchingFiles.forEach((file, index2) => { const radioElement = document.createElement("input"); radioElement.type = "radio"; radioElement.name = "fileOption"; radioElement.value = file.path; radioElement.id = `file-${index2}`; const labelElement = document.createElement("label"); labelElement.htmlFor = `file-${index2}`; labelElement.textContent = file.path; optionsContainer.appendChild(radioElement); optionsContainer.appendChild(labelElement); optionsContainer.appendChild(document.createElement("br")); }); modalContent.appendChild(optionsContainer); const confirmLoadButton = document.createElement("button"); confirmLoadButton.id = "confirmLoad"; confirmLoadButton.textContent = "Load"; modalContent.appendChild(confirmLoadButton); confirmLoadButton == null ? void 0 : confirmLoadButton.addEventListener("click", async function() { const selectedRadio = optionsContainer.querySelector('input[type="radio"]:checked'); if (selectedRadio) { const selectedFilePath = selectedRadio.value; const selectedFile = matchingFiles.find((file) => file.path === selectedFilePath); if (selectedFile) { const chatHistoryFilePath = selectedFile.path; const success = await loadChatHistory(chatHistoryFilePath); if (success) { new import_obsidian6.Notice(`Switched to '${selectedFile.path}' chat history.`); lastLoadedChatHistoryFile = selectedFile; settings.profiles.lastLoadedChatHistoryPath = selectedFile.path; settings.profiles.lastLoadedChatHistory[profileIndex] = settings.profiles.lastLoadedChatHistoryPath; await plugin.saveSettings(); } modal.close(); } } }); } modal.contentEl.appendChild(modalContent); modal.open(); } else if (Object.values(loadAliases).map((v) => v.toLowerCase()).includes(inputValue.toLowerCase())) { const matchedFile = Object.entries(loadAliases).find(([key, value]) => value.toLowerCase() === inputValue.toLowerCase()); if (matchedFile) { const matchingFiles = files.filter((file) => file.name.includes(matchedFile[1])); const modal = new import_obsidian6.Modal(plugin.app); const modalContent = document.createElement("div"); modalContent.classList.add("modal-content"); const heading = document.createElement("h2"); heading.textContent = "Load Chat History"; modalContent.appendChild(heading); if (matchingFiles.length === 1) { const message = document.createElement("p"); message.textContent = `Are you sure you want to override your current chat history with "${matchingFiles[0].name}"?`; modalContent.appendChild(message); const confirmLoadButton = document.createElement("button"); confirmLoadButton.id = "confirmLoad"; confirmLoadButton.textContent = "Confirm"; modalContent.appendChild(confirmLoadButton); confirmLoadButton == null ? void 0 : confirmLoadButton.addEventListener("click", async function() { const selectedFile = matchingFiles[0]; const chatHistoryFilePath = selectedFile.path; const success = await loadChatHistory(chatHistoryFilePath); if (success) { new import_obsidian6.Notice(`Switched to '${selectedFile.path}' chat history.`); lastLoadedChatHistoryFile = selectedFile; settings.profiles.lastLoadedChatHistoryPath = selectedFile.path; settings.profiles.lastLoadedChatHistory[profileIndex] = settings.profiles.lastLoadedChatHistoryPath; await plugin.saveSettings(); } modal.close(); }); } else { const message = document.createElement("p"); message.textContent = "Select a chat history to override:"; modalContent.appendChild(message); const optionsContainer = document.createElement("div"); optionsContainer.classList.add("file-options"); optionsContainer.style.marginBottom = "16px"; matchingFiles.forEach((file, index2) => { const radioElement = document.createElement("input"); radioElement.type = "radio"; radioElement.name = "fileOption"; radioElement.value = file.path; radioElement.id = `file-${index2}`; const labelElement = document.createElement("label"); labelElement.htmlFor = `file-${index2}`; labelElement.textContent = file.path; optionsContainer.appendChild(radioElement); optionsContainer.appendChild(labelElement); optionsContainer.appendChild(document.createElement("br")); }); modalContent.appendChild(optionsContainer); const confirmLoadButton = document.createElement("button"); confirmLoadButton.id = "confirmLoad"; confirmLoadButton.textContent = "Load"; modalContent.appendChild(confirmLoadButton); confirmLoadButton == null ? void 0 : confirmLoadButton.addEventListener("click", async function() { const selectedRadio = optionsContainer.querySelector('input[type="radio"]:checked'); if (selectedRadio) { const selectedFilePath = selectedRadio.value; const selectedFile = matchingFiles.find((file) => file.path === selectedFilePath); if (selectedFile) { const chatHistoryFilePath = selectedFile.path; const success = await loadChatHistory(chatHistoryFilePath); if (success) { new import_obsidian6.Notice(`Switched to '${selectedFile.path}' chat history.`); lastLoadedChatHistoryFile = selectedFile; settings.profiles.lastLoadedChatHistoryPath = selectedFile.path; settings.profiles.lastLoadedChatHistory[profileIndex] = settings.profiles.lastLoadedChatHistoryPath; await plugin.saveSettings(); } modal.close(); } } }); } modal.contentEl.appendChild(modalContent); modal.open(); } } else { new import_obsidian6.Notice("File does not exist."); } } } function commandStop() { const controller = getAbortController(); if (controller) { controller.abort(); } } async function removeMessageThread(plugin, index2) { const messageContainer = document.querySelector("#messageContainer"); const divElements = messageContainer == null ? void 0 : messageContainer.querySelectorAll("div.botMessage, div.userMessage"); if (divElements && divElements.length > 0 && index2 >= 0 && index2 < divElements.length) { for (let i = index2; i < divElements.length; i++) { messageContainer == null ? void 0 : messageContainer.removeChild(divElements[i]); } } messageHistory.splice(index2); const jsonString = JSON.stringify(messageHistory, null, 4); try { await plugin.app.vault.adapter.write(fileNameMessageHistoryJson(plugin), jsonString); const profileFiles = plugin.app.vault.getFiles().filter((file) => file.path.startsWith(plugin.settings.profiles.profileFolderPath)); profileFiles.sort((a, b) => a.name.localeCompare(b.name)); const currentProfile = plugin.settings.profiles.profile.replace(/\.[^/.]+$/, ""); const profileIndex = profileFiles.findIndex((file) => file.basename === currentProfile); lastLoadedChatHistoryFile = null; plugin.settings.profiles.lastLoadedChatHistoryPath = null; plugin.settings.profiles.lastLoadedChatHistory[profileIndex] = plugin.settings.profiles.lastLoadedChatHistoryPath; await plugin.saveSettings(); new import_obsidian6.Notice("Chat history cleared."); } catch (error) { console.error("Error writing messageHistory.json", error); } } // src/components/chat/UserMessage.ts function displayUserMessage(plugin, settings, message) { let trimmedMessage = message.trim(); const userMessageDiv = document.createElement("div"); userMessageDiv.className = "userMessage"; userMessageDiv.style.backgroundColor = colorToHex(settings.appearance.userMessageBackgroundColor || getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.userMessageBackgroundColor).trim()); userMessageDiv.style.color = settings.appearance.userMessageFontColor || DEFAULT_SETTINGS.appearance.userMessageFontColor; const userMessageToolBarDiv = document.createElement("div"); userMessageToolBarDiv.className = "userMessageToolBar"; const buttonContainerDiv = document.createElement("div"); buttonContainerDiv.className = "button-container"; const userNameSpan = document.createElement("span"); userNameSpan.className = "userName"; userNameSpan.textContent = settings.appearance.userName || DEFAULT_SETTINGS.appearance.userName; userMessageToolBarDiv.appendChild(userNameSpan); userMessageToolBarDiv.appendChild(buttonContainerDiv); const userPre = document.createElement("pre"); const preUserMessage = document.createElement("span"); preUserMessage.className = "preUserMessage"; userPre.appendChild(preUserMessage); const regexRenderedNote = /[\s\S]*?<\/note-rendered>/g; trimmedMessage = trimmedMessage.replace(regexRenderedNote, "").trim(); preUserMessage.innerHTML = trimmedMessage; const regenerateButton = regenerateUserButton(plugin, settings); const editButton = displayUserEditButton(plugin, settings, userPre); const copyUserButton = displayUserCopyButton(userPre); const trashButton = displayTrashButton(plugin); if (!message.startsWith("/")) { buttonContainerDiv.appendChild(regenerateButton); buttonContainerDiv.appendChild(editButton); } buttonContainerDiv.appendChild(copyUserButton); buttonContainerDiv.appendChild(trashButton); userMessageDiv.appendChild(userMessageToolBarDiv); userMessageDiv.appendChild(userPre); return userMessageDiv; } // src/view.ts var VIEW_TYPE_CHATBOT = "chatbot-view"; var ANTHROPIC_MODELS = ["claude-instant-1.2", "claude-2.0", "claude-2.1", "claude-3-haiku-20240307", "claude-3-sonnet-20240229", "claude-3-5-sonnet-20240620", "claude-3-opus-20240229"]; var OPENAI_MODELS = ["gpt-3.5-turbo", "gpt-4", "gpt-4-turbo", "gpt-4o", "gpt-4o-mini"]; function fileNameMessageHistoryJson(plugin) { const filenameMessageHistoryPath = "./.obsidian/plugins/bmo-chatbot/data/"; const currentProfileMessageHistory = "messageHistory_" + plugin.settings.profiles.profile.replace(".md", ".json"); return filenameMessageHistoryPath + currentProfileMessageHistory; } var messageHistory = []; var lastCursorPosition = { line: 0, ch: 0 }; var lastCursorPositionFile = null; var activeEditor = null; var BMOView = class extends import_obsidian7.ItemView { constructor(leaf, settings, plugin) { super(leaf); this.preventEnter = false; this.settings = settings; this.plugin = plugin; this.icon = "bot"; this.addCursorLogging(); } getViewType() { return VIEW_TYPE_CHATBOT; } getDisplayText() { return "BMO Chatbot"; } async onOpen() { const container = this.containerEl.children[1]; container.empty(); const chatbotContainer = container.createEl("div", { attr: { class: "chatbotContainer" } }); const header = chatbotContainer.createEl("div", { attr: { id: "header" } }); const chatbotNameHeading = chatbotContainer.createEl("h1", { text: this.settings.appearance.chatbotName || DEFAULT_SETTINGS.appearance.chatbotName, attr: { id: "chatbotNameHeading" } }); const modelOptions = populateModelDropdown(this.plugin, this.settings); const dotIndicator = chatbotContainer.createEl("span", { attr: { class: "dotIndicator", id: "markDownBoolean" } }); const referenceCurrentNoteElement = chatbotContainer.createEl("p", { text: "Reference Current Note", attr: { id: "referenceCurrentNote" } }); header.appendChild(chatbotNameHeading); header.appendChild(modelOptions); referenceCurrentNoteElement.appendChild(dotIndicator); referenceCurrentNoteElement.style.display = "none"; if (referenceCurrentNoteElement) { if (this.settings.general.enableReferenceCurrentNote) { referenceCurrentNoteElement.style.display = "block"; } else { referenceCurrentNoteElement.style.display = "none"; } } const messageContainer = chatbotContainer.createEl("div", { attr: { id: "messageContainer" } }); if (this.settings.appearance.enableHeader) { header.style.display = "block"; } else { header.style.display = "none"; messageContainer.style.maxHeight = "calc(100% - 60px)"; referenceCurrentNoteElement.style.margin = "0.5rem 0 0.5rem 0"; } await loadData(this.plugin); messageContainer.id = "messageContainer"; messageHistory.forEach(async (messageData) => { if (messageData.role == "user") { const userMessageDiv = displayUserMessage(this.plugin, this.settings, messageData.content); messageContainer.appendChild(userMessageDiv); } if (messageData.role == "assistant") { const botMessageDiv = displayBotMessage(this.plugin, this.settings, messageHistory, messageData.content); updateUnresolvedInternalLinks(this.plugin, botMessageDiv); messageContainer.appendChild(botMessageDiv); } }); messageContainer.addEventListener("click", (event) => { const target = event.target; if (target.tagName === "A" && target.classList.contains("internal-link")) { const link = target; const linkName = link.getAttribute("data-href") || ""; this.plugin.app.workspace.openLinkText(linkName, "", false); link.style.color = "var(--link-color)"; } }); const parentElement = document.getElementById("parentElementId"); parentElement == null ? void 0 : parentElement.appendChild(messageContainer); const chatbox = chatbotContainer.createEl("div", { attr: { class: "chatbox" } }); const textarea = document.createElement("textarea"); textarea.setAttribute("contenteditable", true.toString()); textarea.setAttribute("placeholder", "Start typing..."); if (textarea) { textarea.style.color = this.settings.appearance.chatBoxFontColor; const style = document.createElement("style"); style.textContent = ` .chatbox textarea::placeholder { color: ${this.settings.appearance.chatBoxFontColor} !important; } `; textarea.appendChild(style); } const submitButton = document.createElement("button"); submitButton.textContent = "send"; (0, import_obsidian7.setIcon)(submitButton, "arrow-up"); submitButton.classList.add("submit-button"); submitButton.title = "send"; submitButton.addEventListener("click", () => { this.handleKeyup(new KeyboardEvent("keyup", { key: "Enter" }), true); }); chatbotContainer.style.backgroundColor = this.settings.appearance.chatbotContainerBackgroundColor || DEFAULT_SETTINGS.appearance.chatbotContainerBackgroundColor; messageContainer.style.backgroundColor = this.settings.appearance.messageContainerBackgroundColor || DEFAULT_SETTINGS.appearance.messageContainerBackgroundColor; textarea.style.backgroundColor = this.settings.appearance.chatBoxBackgroundColor || DEFAULT_SETTINGS.appearance.chatBoxBackgroundColor; textarea.style.borderColor = this.settings.appearance.chatBoxBackgroundColor || DEFAULT_SETTINGS.appearance.chatBoxBackgroundColor; textarea.style.color = this.settings.appearance.chatBoxFontColor || DEFAULT_SETTINGS.appearance.chatBoxFontColor; chatbox.style.backgroundColor = this.settings.appearance.chatBoxBackgroundColor || DEFAULT_SETTINGS.appearance.chatBoxBackgroundColor; submitButton.style.backgroundColor = this.settings.appearance.chatBoxBackgroundColor || DEFAULT_SETTINGS.appearance.chatBoxBackgroundColor; const userMessages = messageContainer.querySelectorAll(".userMessage"); userMessages.forEach((userMessage) => { userMessage.style.color = this.settings.appearance.userMessageFontColor || DEFAULT_SETTINGS.appearance.userMessageFontColor; }); const botMessages = messageContainer.querySelectorAll(".botMessage"); botMessages.forEach((botMessage) => { botMessage.style.color = this.settings.appearance.botMessageFontColor || DEFAULT_SETTINGS.appearance.botMessageFontColor; }); chatbox.appendChild(textarea); chatbox.appendChild(submitButton); this.textareaElement = textarea; this.addEventListeners(); messageContainer.scrollTop = messageContainer.scrollHeight; } addEventListeners() { this.textareaElement.addEventListener("keyup", this.handleKeyup.bind(this)); this.textareaElement.addEventListener("keydown", this.handleKeydown.bind(this)); this.textareaElement.addEventListener("input", this.handleInput.bind(this)); this.textareaElement.addEventListener("blur", this.handleBlur.bind(this)); } async handleKeyup(event, fromSubmitButton = false) { if ((document.body.classList.contains("is-mobile") || document.body.classList.contains("is-tablet")) && event.key === "Enter" && !fromSubmitButton) { event.preventDefault(); this.textareaElement.value += "\n"; this.handleInput(event); return; } const input = this.textareaElement.value; const index2 = messageHistory.length - 1; if (this.settings.OllamaConnection.enableStream || this.settings.RESTAPIURLConnection.enableStream || this.settings.APIConnections.mistral.enableStream || this.settings.APIConnections.openAI.enableStream) { if ((input === "/s" || input === "/stop") && event.key === "Enter") { this.preventEnter = false; await executeCommand(input, this.settings, this.plugin); } } const regex = /(!?)\[\[(.*?)\]\]/g; let matches; let inputModified = input; const replacements = /* @__PURE__ */ new Map(); while ((matches = regex.exec(input)) !== null) { const exclamation = matches[1]; const linktext = matches[2]; const [path, subpath] = linktext.split("#"); const file = this.plugin.app.metadataCache.getFirstLinkpathDest(path, ""); if (file && file instanceof import_obsidian7.TFile) { try { const filePath = file.path; const fileExtension = filePath.split(".").pop(); if (fileExtension !== "md") { const isImageFile = /\.(jpg|jpeg|png|gif|webp|bmp|tiff|tif|svg)$/i.test(filePath); if (!this.plugin.settings.OllamaConnection.ollamaModels.includes(this.plugin.settings.general.model)) { replacements.set(matches[0], `${exclamation}[[${matches[2]}]]ERROR: File cannot be read.`); } else if (this.plugin.settings.OllamaConnection.ollamaModels.includes(this.plugin.settings.general.model)) { if (!isImageFile) { replacements.set(matches[0], `${exclamation}[[${matches[2]}]]ERROR: File cannot be read.`); } } continue; } const content = await this.app.vault.read(file); let contentToInsert = content; if (subpath) { const lines = content.split("\n"); let inSubpath = false; const subpathContent = []; let subpathLevel = 0; for (const line of lines) { if (line.startsWith("#")) { const match = line.match(/^#+/); const headingLevel = match ? match[0].length : 0; if (inSubpath) { if (headingLevel <= subpathLevel) { break; } } if (!inSubpath && line.toLowerCase().includes(subpath.toLowerCase())) { inSubpath = true; subpathLevel = headingLevel; } } if (inSubpath) { subpathContent.push(line); } } contentToInsert = subpathContent.join("\n"); } replacements.set(matches[0], `${exclamation}[[${matches[2]}]]${contentToInsert}`); } catch (err) { console.error(`Failed to read the content of "${path}": ${err}`); } } else { replacements.set(matches[0], `${exclamation}[[${matches[2]}]]File cannot be read.`); } } for (const [original, replacement] of replacements) { inputModified = inputModified.split(original).join(replacement); } inputModified = inputModified.replace(/(File cannot be read.<\/note-rendered>)+/g, "File cannot be read."); if (this.preventEnter === false && !event.shiftKey && event.key === "Enter") { loadData(this.plugin); event.preventDefault(); if (input.length === 0) { return; } const messageContainer = document.querySelector("#messageContainer"); if (messageContainer) { const excludedCommands = [ "/c", "/clear", "/s", "/stop", "/save", "/load ", "/m ", "/model ", "/models ", "/p ", "/profile ", "/prof ", "/profiles ", "/prompt ", "/prompts ", "/append", "/reference ", "/ref ", "/maxtokens", "/maxtokens ", "/temperature", "/temperature ", "/temp", "/temp " ]; if (!excludedCommands.some((cmd) => input.startsWith(cmd))) { const parts = input.split(" "); const baseCommand = parts[0]; if (baseCommand.startsWith("/") && commandMap.hasOwnProperty(baseCommand)) { addMessage(this.plugin, input, "userMessage", this.settings, index2); const userMessageDiv = displayUserMessage(this.plugin, this.settings, input); messageContainer.appendChild(userMessageDiv); } else if (!baseCommand.startsWith("/")) { addMessage(this.plugin, inputModified, "userMessage", this.settings, index2); const userMessageDiv = displayUserMessage(this.plugin, this.settings, input); messageContainer.appendChild(userMessageDiv); } else { } } if (input.startsWith("/")) { executeCommand(input, this.settings, this.plugin); if (!excludedCommands.some((cmd) => input.startsWith(cmd))) { const botMessages = messageContainer.querySelectorAll(".botMessage"); const lastBotMessage = botMessages[botMessages.length - 1]; lastBotMessage.scrollIntoView({ behavior: "smooth", block: "start" }); } } else { this.preventEnter = true; this.BMOchatbot().then(() => { this.preventEnter = false; }).catch(() => { const messageContainer2 = document.querySelector("#messageContainer"); const botMessageDiv = displayErrorBotMessage(this.plugin, this.settings, messageHistory, "Oops, something went wrong. Please try again."); messageContainer2.appendChild(botMessageDiv); }); } } this.textareaElement.value = ""; this.textareaElement.style.height = "29px"; this.textareaElement.value = this.textareaElement.value.trim(); this.textareaElement.setSelectionRange(0, 0); } } handleKeydown(event) { if (event.key === "Enter" && !event.shiftKey) { event.preventDefault(); } } handleInput(event) { this.textareaElement.style.height = "29px"; this.textareaElement.style.height = this.textareaElement.scrollHeight + "px"; } handleBlur(event) { if (!this.textareaElement.value) { this.textareaElement.style.height = "29px"; } } exportSettings() { return this.settings; } addCursorLogging() { const updateCursorPosition = async () => { await getActiveFileContent(this.plugin, this.settings); const view = this.plugin.app.workspace.getActiveViewOfType(import_obsidian7.MarkdownView); if (view) { const cursor = view.editor.getCursor(); lastCursorPositionFile = this.plugin.app.workspace.getActiveFile(); if (cursor != null && this.plugin.app.workspace.activeEditor != null) { lastCursorPosition = cursor; activeEditor = view.editor; } } }; activeWindow.addEventListener("click", updateCursorPosition); activeWindow.addEventListener("keyup", updateCursorPosition); activeWindow.addEventListener("keydown", updateCursorPosition); activeWindow.addEventListener("input", updateCursorPosition); } cleanup() { this.textareaElement.removeEventListener("keyup", this.handleKeyup.bind(this)); this.textareaElement.addEventListener("keydown", this.handleKeydown.bind(this)); this.textareaElement.removeEventListener("input", this.handleInput.bind(this)); this.textareaElement.removeEventListener("blur", this.handleBlur.bind(this)); } async BMOchatbot() { await getActiveFileContent(this.plugin, this.settings); const index2 = messageHistory.length - 1; if (this.settings.general.model === "") { const errorMessage = "Model not found."; const messageContainer = document.querySelector("#messageContainer"); const botMessageDiv = displayErrorBotMessage(this.plugin, this.settings, messageHistory, errorMessage); messageContainer.appendChild(botMessageDiv); const botMessages = messageContainer.querySelectorAll(".botMessage"); const lastBotMessage = botMessages[botMessages.length - 1]; lastBotMessage.scrollIntoView({ behavior: "smooth", block: "start" }); } else { if (this.settings.OllamaConnection.ollamaModels.includes(this.settings.general.model)) { if (this.settings.OllamaConnection.enableStream) { await fetchOllamaResponseStream(this.plugin, this.settings, index2); } else { await fetchOllamaResponse(this.plugin, this.settings, index2); } } else if (this.settings.RESTAPIURLConnection.RESTAPIURLModels.includes(this.settings.general.model)) { if (this.settings.RESTAPIURLConnection.enableStream) { await fetchRESTAPIURLResponseStream(this.plugin, this.settings, index2); } else { await fetchRESTAPIURLResponse(this.plugin, this.settings, index2); } } else if (ANTHROPIC_MODELS.includes(this.settings.general.model)) { await fetchAnthropicResponse(this.plugin, this.settings, index2); } else if (this.settings.APIConnections.mistral.mistralModels.includes(this.settings.general.model)) { if (this.settings.APIConnections.mistral.enableStream) { await fetchMistralResponseStream(this.plugin, this.settings, index2); } else { await fetchMistralResponse(this.plugin, this.settings, index2); } } else if (this.settings.APIConnections.googleGemini.geminiModels.includes(this.settings.general.model)) { if (this.settings.APIConnections.googleGemini.enableStream) { await fetchGoogleGeminiResponseStream(this.plugin, this.settings, index2); } else { await fetchGoogleGeminiResponse(this.plugin, this.settings, index2); } } else if (this.settings.APIConnections.openAI.openAIBaseModels.includes(this.settings.general.model)) { if (this.settings.APIConnections.openAI.enableStream) { await fetchOpenAIAPIResponseStream(this.plugin, this.settings, index2); } else { await fetchOpenAIAPIResponse(this.plugin, this.settings, index2); } } else if (this.settings.APIConnections.openRouter.openRouterModels.includes(this.settings.general.model)) { if (this.settings.APIConnections.openRouter.enableStream) { await fetchOpenRouterResponseStream(this.plugin, this.settings, index2); } else { await fetchOpenRouterResponse(this.plugin, this.settings, index2); } } else { const errorMessage = "Connection not found."; const messageContainer = document.querySelector("#messageContainer"); const botMessageDiv = displayErrorBotMessage(this.plugin, this.settings, messageHistory, errorMessage); messageContainer.appendChild(botMessageDiv); const botMessages = messageContainer.querySelectorAll(".botMessage"); const lastBotMessage = botMessages[botMessages.length - 1]; lastBotMessage.scrollIntoView({ behavior: "smooth", block: "start" }); } } } async onClose() { } }; async function loadData(plugin) { if (!await plugin.app.vault.adapter.exists("./.obsidian/plugins/bmo-chatbot/data/")) { plugin.app.vault.adapter.mkdir("./.obsidian/plugins/bmo-chatbot/data/"); } if (await plugin.app.vault.adapter.exists(fileNameMessageHistoryJson(plugin))) { try { const fileContent = await plugin.app.vault.adapter.read(fileNameMessageHistoryJson(plugin)); if (fileContent.trim() === "") { messageHistory = []; } else { messageHistory = JSON.parse(fileContent); } } catch (error) { console.error("Error processing message history:", error); } } else { messageHistory = []; } } function populateModelDropdown(plugin, settings) { const modelOptions = document.createElement("select"); modelOptions.id = "modelOptions"; if (modelOptions) { modelOptions.innerHTML = ""; } const defaultModel = settings.general.model || DEFAULT_SETTINGS.general.model; const modelGroups = [ { name: "Ollama Models", models: settings.OllamaConnection.ollamaModels }, { name: "REST API Models", models: settings.RESTAPIURLConnection.RESTAPIURLModels }, { name: "Anthropic Models", models: settings.APIConnections.anthropic.anthropicModels }, { name: "Google Gemini Models", models: settings.APIConnections.googleGemini.geminiModels }, { name: "Mistral Models", models: settings.APIConnections.mistral.mistralModels }, { name: "OpenAI-Based Models", models: settings.APIConnections.openAI.openAIBaseModels }, { name: "OpenRouter Models", models: settings.APIConnections.openRouter.openRouterModels } ]; if (defaultModel === "") { const optionEl = document.createElement("option"); optionEl.textContent = "No Model"; optionEl.value = ""; optionEl.selected = true; modelOptions.appendChild(optionEl); } modelGroups.forEach((group) => { if (group.models.length > 0) { const optgroup = document.createElement("optgroup"); optgroup.label = group.name; group.models.forEach((model) => { const optionEl = document.createElement("option"); optionEl.textContent = model; optionEl.value = model; if (model === defaultModel) { optionEl.selected = true; } optgroup.appendChild(optionEl); }); modelOptions.appendChild(optgroup); } }); modelOptions.addEventListener("change", async function() { plugin.settings.general.model = this.value; await plugin.saveSettings(); }); return modelOptions; } // src/settings.ts var import_obsidian23 = require("obsidian"); // src/components/settings/GeneralSettings.ts var import_obsidian9 = require("obsidian"); // src/components/FetchModelList.ts var import_obsidian8 = require("obsidian"); async function fetchOllamaModels(plugin) { const ollamaRESTAPIURL = plugin.settings.OllamaConnection.RESTAPIURL; try { const ollama = new Ollama2({ host: ollamaRESTAPIURL }); const modelsList = await ollama.list(); const models = modelsList.models.map((model) => model.name); plugin.settings.OllamaConnection.ollamaModels = models; return models; } catch (error) { console.error("Error fetching models from Ollama:", error); return; } } async function fetchRESTAPIURLModels(plugin) { const RESTAPIURL = plugin.settings.RESTAPIURLConnection.RESTAPIURL; try { new URL(RESTAPIURL); } catch (error) { console.error("Invalid REST API URL:", RESTAPIURL); return; } try { const response = await (0, import_obsidian8.requestUrl)({ url: RESTAPIURL + "/models", method: "GET", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${plugin.settings.RESTAPIURLConnection.APIKey}` } }); if (response.json && (response.json.data || Array.isArray(response.json))) { let models; if (Array.isArray(response.json)) { models = response.json.map((model) => model.id); } else { models = response.json.data.map((model) => model.id); } plugin.settings.RESTAPIURLConnection.RESTAPIURLModels = models; return models; } } catch (error) { console.error("Error making API request:", error); throw error; } } async function fetchGoogleGeminiModels(plugin) { try { const API_KEY = plugin.settings.APIConnections.googleGemini.APIKey; const response = await (0, import_obsidian8.requestUrl)({ url: `https://generativelanguage.googleapis.com/v1beta/models?key=${API_KEY}`, method: "GET", headers: { "Content-Type": "application/json" } }); if (response.json && response.json.models) { const models = response.json.models.map((model) => model.name).filter((model) => model.startsWith("models/gemini")); plugin.settings.APIConnections.googleGemini.geminiModels = models; return models; } } catch (error) { console.error(error); } } async function fetchMistralModels(plugin) { try { const response = await (0, import_obsidian8.requestUrl)({ url: "https://api.mistral.ai/v1/models", method: "GET", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${plugin.settings.APIConnections.mistral.APIKey}` } }); if (response.json && response.json.data) { const models = response.json.data.map((model) => model.id); plugin.settings.APIConnections.mistral.mistralModels = models; console.log(models); return models; } } catch (error) { console.error(error); } } async function fetchOpenAIBaseModels(plugin) { const openai = new openai_default({ apiKey: plugin.settings.APIConnections.openAI.APIKey, baseURL: plugin.settings.APIConnections.openAI.openAIBaseUrl, dangerouslyAllowBrowser: true // apiKey is stored within data.json }); const list = await openai.models.list(); if (openai.baseURL == "https://api.openai.com/v1") { plugin.settings.APIConnections.openAI.openAIBaseModels = OPENAI_MODELS; return OPENAI_MODELS; } else { const models = list.data.map((model) => model.id); plugin.settings.APIConnections.openAI.openAIBaseModels = models; return models; } } async function fetchOpenRouterModels(plugin) { try { const response = await (0, import_obsidian8.requestUrl)({ url: "https://openrouter.ai/api/v1/models", method: "GET", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${plugin.settings.APIConnections.openRouter.APIKey}` } }); if (response.json && (response.json.data || Array.isArray(response.json))) { let models; if (Array.isArray(response.json)) { models = response.json.map((model) => model.id); } else { models = response.json.data.map((model) => model.id); } plugin.settings.APIConnections.openRouter.openRouterModels = models; return models; } } catch (error) { console.error("Error making API request:", error); throw error; } } // src/components/settings/GeneralSettings.ts async function addGeneralSettings(containerEl, plugin, SettingTab15) { const toggleSettingContainer = containerEl.createDiv({ cls: "toggleSettingContainer" }); toggleSettingContainer.createEl("h2", { text: "General" }); const initialState = plugin.settings.toggleGeneralSettings; const chevronIcon = toggleSettingContainer.createEl("span", { cls: "chevron-icon" }); (0, import_obsidian9.setIcon)(chevronIcon, initialState ? "chevron-down" : "chevron-right"); const settingsContainer = containerEl.createDiv({ cls: "settingsContainer" }); settingsContainer.style.display = initialState ? "block" : "none"; toggleSettingContainer.addEventListener("click", async () => { const isOpen = settingsContainer.style.display !== "none"; if (isOpen) { (0, import_obsidian9.setIcon)(chevronIcon, "chevron-right"); settingsContainer.style.display = "none"; plugin.settings.toggleGeneralSettings = false; } else { (0, import_obsidian9.setIcon)(chevronIcon, "chevron-down"); settingsContainer.style.display = "block"; plugin.settings.toggleGeneralSettings = true; } await plugin.saveSettings(); }); const createModelDropdown = (dropdown) => { const modelGroups = [ { name: "Ollama Models", models: plugin.settings.OllamaConnection.ollamaModels }, { name: "REST API Models", models: plugin.settings.RESTAPIURLConnection.RESTAPIURLModels }, { name: "Anthropic Models", models: plugin.settings.APIConnections.anthropic.anthropicModels }, { name: "Google Gemini Models", models: plugin.settings.APIConnections.googleGemini.geminiModels }, { name: "Mistral Models", models: plugin.settings.APIConnections.mistral.mistralModels }, { name: "OpenAI-Based Models", models: plugin.settings.APIConnections.openAI.openAIBaseModels }, { name: "OpenRouter Models", models: plugin.settings.APIConnections.openRouter.openRouterModels } ]; const selectEl = dropdown.selectEl; selectEl.innerHTML = ""; const defaultOption = selectEl.createEl("option", { value: "", text: "No Model" }); if (plugin.settings.general.model === "No Model") { defaultOption.selected = true; } modelGroups.forEach((group) => { if (group.models.length > 0) { const optgroup = selectEl.createEl("optgroup"); optgroup.label = group.name; group.models.forEach((model) => { const option = optgroup.createEl("option", { value: model, text: model }); if (model === plugin.settings.general.model) { option.selected = true; } }); } }); dropdown.onChange(async (value) => { plugin.settings.general.model = value; await plugin.saveSettings(); }); }; let modelDropdown; new import_obsidian9.Setting(settingsContainer).setName("Model").setDesc("Choose a model.").addButton( (button) => button.setButtonText("Restore Default").setIcon("rotate-cw").setClass("clickable-icon").onClick(async () => { new import_obsidian9.Notice("Reloading..."); if (plugin.settings.OllamaConnection.RESTAPIURL !== "") { const models = await fetchOllamaModels(plugin); plugin.settings.OllamaConnection.ollamaModels = models || []; } if (plugin.settings.RESTAPIURLConnection.RESTAPIURL !== "") { const models = await fetchRESTAPIURLModels(plugin); plugin.settings.RESTAPIURLConnection.RESTAPIURLModels = models || []; } if (plugin.settings.APIConnections.anthropic.APIKey !== "") { const models = ANTHROPIC_MODELS; plugin.settings.APIConnections.anthropic.anthropicModels = models || []; } if (plugin.settings.APIConnections.googleGemini.APIKey !== "") { const models = await fetchGoogleGeminiModels(plugin); plugin.settings.APIConnections.googleGemini.geminiModels = models || []; } if (plugin.settings.APIConnections.mistral.APIKey !== "") { const models = await fetchMistralModels(plugin); plugin.settings.APIConnections.mistral.mistralModels = models || []; } if (plugin.settings.APIConnections.openAI.APIKey !== "" || plugin.settings.APIConnections.openAI.openAIBaseUrl != DEFAULT_SETTINGS.APIConnections.openAI.openAIBaseUrl) { const models = await fetchOpenAIBaseModels(plugin); plugin.settings.APIConnections.openAI.openAIBaseModels = models || []; } if (plugin.settings.APIConnections.openRouter.APIKey !== "") { const models = await fetchOpenRouterModels(plugin); plugin.settings.APIConnections.openRouter.openRouterModels = models || []; } if (modelDropdown) { createModelDropdown(modelDropdown); } new import_obsidian9.Notice("Models reloaded."); }) ).addDropdown((dropdown) => { modelDropdown = dropdown; createModelDropdown(dropdown); }); new import_obsidian9.Setting(settingsContainer).setName("Max Tokens").setDesc("The maximum number of tokens, or words, that the model is allowed to generate in its output. Some models require a minimum number of tokens to be set. The default value is empty.").addText( (text) => text.setPlaceholder("4096").setValue(plugin.settings.general.max_tokens).onChange(async (value) => { plugin.settings.general.max_tokens = value; await plugin.saveSettings(); }) ); new import_obsidian9.Setting(settingsContainer).setName("Temperature").setDesc("Temperature controls how random the generated output is. Lower values make the text more predictable, while higher values make it more creative and unpredictable.").addText( (text) => text.setPlaceholder("1.00").setValue(plugin.settings.general.temperature).onChange(async (value) => { const floatValue = parseFloat(value); if (!isNaN(floatValue)) { if (!isNaN(floatValue)) { if (floatValue < 0) { plugin.settings.general.temperature = "0.00"; } else if (floatValue > 2) { plugin.settings.general.temperature = "2.00"; } else { plugin.settings.general.temperature = floatValue.toFixed(2); } } else { plugin.settings.general.temperature = DEFAULT_SETTINGS.general.temperature; } } else { plugin.settings.general.temperature = DEFAULT_SETTINGS.general.temperature; } await plugin.saveSettings(); }).inputEl.addEventListener("focusout", async () => { SettingTab15.display(); }) ); new import_obsidian9.Setting(settingsContainer).setName("Enable Reference Current Note").setDesc("Enable chatbot to reference current active note during conversation.").addToggle( (toggle) => toggle.setValue(plugin.settings.general.enableReferenceCurrentNote).onChange((value) => { plugin.settings.general.enableReferenceCurrentNote = value; plugin.saveSettings(); const referenceCurrentNoteElement = document.getElementById("referenceCurrentNote"); if (referenceCurrentNoteElement) { if (value) { referenceCurrentNoteElement.style.display = "block"; } else { referenceCurrentNoteElement.style.display = "none"; } } }) ); } // src/components/settings/AppearanceSettings.ts var import_obsidian10 = require("obsidian"); function addAppearanceSettings(containerEl, plugin, SettingTab15) { const toggleSettingContainer = containerEl.createDiv({ cls: "toggleSettingContainer" }); toggleSettingContainer.createEl("h2", { text: "Appearance" }); const initialState = plugin.settings.toggleAppearanceSettings; const chevronIcon = toggleSettingContainer.createEl("span", { cls: "chevron-icon" }); (0, import_obsidian10.setIcon)(chevronIcon, initialState ? "chevron-down" : "chevron-right"); const settingsContainer = containerEl.createDiv({ cls: "settingsContainer" }); settingsContainer.style.display = initialState ? "block" : "none"; toggleSettingContainer.addEventListener("click", async () => { const isOpen = settingsContainer.style.display !== "none"; if (isOpen) { (0, import_obsidian10.setIcon)(chevronIcon, "chevron-right"); settingsContainer.style.display = "none"; plugin.settings.toggleAppearanceSettings = false; } else { (0, import_obsidian10.setIcon)(chevronIcon, "chevron-down"); settingsContainer.style.display = "block"; plugin.settings.toggleAppearanceSettings = true; } await plugin.saveSettings(); }); settingsContainer.createEl("h6", { text: "Chat View" }); new import_obsidian10.Setting(settingsContainer).setName("Enable Header").setDesc("Display chatbot name and model name in header.").addToggle( (toggle) => toggle.setValue(plugin.settings.appearance.enableHeader).onChange((value) => { plugin.settings.appearance.enableHeader = value; const referenceCurrentNoteElement = document.querySelector("#referenceCurrentNote"); if (value === true) { const header = document.querySelector("#header"); if (header) { header.style.display = "block"; referenceCurrentNoteElement.style.margin = "-0.5rem 0 0.5rem 0"; } } else { const header = document.querySelector("#header"); const messageContainer = document.querySelector("#messageContainer"); if (header) { header.style.display = "none"; messageContainer.style.maxHeight = "calc(100% - 60px)"; referenceCurrentNoteElement.style.margin = "0.5rem 0 0.5rem 0"; } } plugin.saveSettings(); }) ); new import_obsidian10.Setting(settingsContainer).setName("User Name").setDesc("Create a username.").addText( (text) => text.setPlaceholder("Enter user name").setValue(plugin.settings.appearance.userName || DEFAULT_SETTINGS.appearance.userName).onChange(async (value) => { plugin.settings.appearance.userName = value ? value : DEFAULT_SETTINGS.appearance.userName; text.inputEl.maxLength = 30; await plugin.saveSettings(); const userNames = document.querySelectorAll(".userName"); userNames.forEach((userName) => { userName.textContent = plugin.settings.appearance.userName; }); }) ); let colorPicker1; const defaultChatbotContainerBackgroundColor = getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.chatbotContainerBackgroundColor).trim(); let colorPicker2; const defaultMessageContainerBackgroundColor = getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.messageContainerBackgroundColor).trim(); let colorPicker3; const defaultUserMessageFontColor = getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.userMessageFontColor).trim(); let colorPicker4; const defaultUserMessageBackgroundColor = getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.userMessageBackgroundColor).trim(); let colorPicker5; const defaultBotMessageFontColor = getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.botMessageFontColor).trim(); let colorPicker6; const defaultBotMessageBackgroundColor = getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.botMessageBackgroundColor).trim(); let colorPicker7; const defaultChatBoxFontColor = getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.chatBoxFontColor).trim(); let colorPicker8; const defaultChatBoxBackgroundColor = getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.chatBoxBackgroundColor).trim(); new import_obsidian10.Setting(settingsContainer).setName("Chatbot Container Background Color").setDesc("Modify the background color of the chatbot container.").addButton( (button) => button.setButtonText("Restore Default").setIcon("rotate-cw").setClass("clickable-icon").onClick(async () => { const defaultValue = colorToHex(defaultChatbotContainerBackgroundColor); colorPicker1.setValue(defaultValue); const chatbotContainer = document.querySelector(".chatbotContainer"); const messageContainer = document.querySelector("#messageContainer"); if (chatbotContainer) { chatbotContainer.style.backgroundColor = defaultValue; messageContainer.style.backgroundColor = colorPicker2.getValue(); await plugin.saveSettings(); } }) ).addColorPicker((color) => { colorPicker1 = color; let defaultValue = plugin.settings.appearance.chatbotContainerBackgroundColor; if (plugin.settings.appearance.chatbotContainerBackgroundColor == "--background-secondary") { defaultValue = colorToHex(defaultChatbotContainerBackgroundColor); } color.setValue(defaultValue).onChange(async (value) => { const hexValue = colorToHex(value); plugin.settings.appearance.chatbotContainerBackgroundColor = hexValue; const chatbotContainer = document.querySelector(".chatbotContainer"); const messageContainer = document.querySelector("#messageContainer"); if (chatbotContainer) { chatbotContainer.style.backgroundColor = hexValue; messageContainer.style.backgroundColor = colorPicker2.getValue(); } await plugin.saveSettings(); }); }); new import_obsidian10.Setting(settingsContainer).setName("Message Container Background Color").setDesc("Modify the background color of the message container.").addButton( (button) => button.setButtonText("Restore Default").setIcon("rotate-cw").setClass("clickable-icon").onClick(async () => { const defaultValue = colorToHex(defaultMessageContainerBackgroundColor); colorPicker2.setValue(defaultValue); const messageContainer = document.querySelector("#messageContainer"); if (messageContainer) { messageContainer.style.backgroundColor = defaultValue; await plugin.saveSettings(); } }) ).addColorPicker((color) => { colorPicker2 = color; let defaultValue = plugin.settings.appearance.messageContainerBackgroundColor; if (plugin.settings.appearance.messageContainerBackgroundColor == "--background-secondary") { defaultValue = colorToHex(defaultMessageContainerBackgroundColor); } color.setValue(defaultValue).onChange(async (value) => { const hexValue = colorToHex(value); plugin.settings.appearance.messageContainerBackgroundColor = hexValue; const messageContainer = document.querySelector("#messageContainer"); if (messageContainer) { messageContainer.style.backgroundColor = hexValue; } await plugin.saveSettings(); }); }); new import_obsidian10.Setting(settingsContainer).setName("User Message Font Color").setDesc("Modify the font color of the user message.").addButton( (button) => button.setButtonText("Restore Default").setIcon("rotate-cw").setClass("clickable-icon").onClick(async () => { const defaultValue = colorToHex(defaultUserMessageFontColor); colorPicker3.setValue(defaultValue); const messageContainer = document.querySelector("#messageContainer"); if (messageContainer) { const userMessages = messageContainer.querySelectorAll(".userMessage"); userMessages.forEach((userMessage) => { const element = userMessage; element.style.color = defaultValue; }); await plugin.saveSettings(); } }) ).addColorPicker((color) => { colorPicker3 = color; let defaultValue = plugin.settings.appearance.userMessageFontColor; if (plugin.settings.appearance.userMessageFontColor == "--text-normal") { defaultValue = colorToHex(defaultUserMessageFontColor); } color.setValue(defaultValue).onChange(async (value) => { const hexValue = colorToHex(value); plugin.settings.appearance.userMessageFontColor = hexValue; const messageContainer = document.querySelector("#messageContainer"); if (messageContainer) { const userMessages = messageContainer.querySelectorAll(".userMessage"); userMessages.forEach((userMessage) => { const element = userMessage; element.style.color = hexValue; }); } await plugin.saveSettings(); }); }); new import_obsidian10.Setting(settingsContainer).setName("User Message Background Color").setDesc("Modify the background color of the user message.").addButton( (button) => button.setButtonText("Restore Default").setIcon("rotate-cw").setClass("clickable-icon").onClick(async () => { const defaultValue = colorToHex(defaultUserMessageBackgroundColor); colorPicker4.setValue(defaultValue); const messageContainer = document.querySelector("#messageContainer"); if (messageContainer) { const userMessages = messageContainer.querySelectorAll(".userMessage"); userMessages.forEach((userMessage) => { const element = userMessage; element.style.backgroundColor = defaultValue; }); await plugin.saveSettings(); } }) ).addColorPicker((color) => { colorPicker4 = color; let defaultValue = plugin.settings.appearance.userMessageBackgroundColor; if (plugin.settings.appearance.userMessageBackgroundColor == "--background-primary") { defaultValue = colorToHex(defaultUserMessageBackgroundColor); } color.setValue(defaultValue).onChange(async (value) => { const hexValue = colorToHex(value); plugin.settings.appearance.userMessageBackgroundColor = hexValue; const messageContainer = document.querySelector("#messageContainer"); if (messageContainer) { const userMessages = messageContainer.querySelectorAll(".userMessage"); userMessages.forEach((userMessage) => { const element = userMessage; element.style.backgroundColor = hexValue; }); } await plugin.saveSettings(); }); }); new import_obsidian10.Setting(settingsContainer).setName("Bot Message Font Color").setDesc("Modify the font color of the bot message.").addButton( (button) => button.setButtonText("Restore Default").setIcon("rotate-cw").setClass("clickable-icon").onClick(async () => { const defaultValue = colorToHex(defaultBotMessageFontColor); colorPicker5.setValue(defaultValue); const messageContainer = document.querySelector("#messageContainer"); if (messageContainer) { const botMessages = messageContainer.querySelectorAll(".botMessage"); botMessages.forEach((botMessage) => { const element = botMessage; element.style.color = defaultValue; }); await plugin.saveSettings(); } }) ).addColorPicker((color) => { colorPicker5 = color; let defaultValue = plugin.settings.appearance.botMessageFontColor; if (plugin.settings.appearance.botMessageFontColor == "--text-normal") { defaultValue = colorToHex(defaultBotMessageFontColor); } color.setValue(defaultValue).onChange(async (value) => { const hexValue = colorToHex(value); plugin.settings.appearance.botMessageFontColor = hexValue; const messageContainer = document.querySelector("#messageContainer"); if (messageContainer) { const botMessages = messageContainer.querySelectorAll(".botMessage"); botMessages.forEach((botMessage) => { const element = botMessage; element.style.color = hexValue; }); } await plugin.saveSettings(); }); }); new import_obsidian10.Setting(settingsContainer).setName("Bot Message Background Color").setDesc("Modify the background color of the bot message.").addButton( (button) => button.setButtonText("Restore Default").setIcon("rotate-cw").setClass("clickable-icon").onClick(async () => { const defaultValue = colorToHex(defaultBotMessageBackgroundColor); colorPicker6.setValue(defaultValue); const messageContainer = document.querySelector("#messageContainer"); if (messageContainer) { const botMessages = messageContainer.querySelectorAll(".botMessage"); botMessages.forEach((botMessage) => { const element = botMessage; element.style.backgroundColor = defaultValue; }); await plugin.saveSettings(); } }) ).addColorPicker((color) => { colorPicker6 = color; let defaultValue = plugin.settings.appearance.botMessageBackgroundColor; if (plugin.settings.appearance.botMessageBackgroundColor == "--background-secondary") { defaultValue = colorToHex(defaultBotMessageBackgroundColor); } color.setValue(defaultValue).onChange(async (value) => { const hexValue = colorToHex(value); plugin.settings.appearance.botMessageBackgroundColor = hexValue; const messageContainer = document.querySelector("#messageContainer"); if (messageContainer) { const botMessages = messageContainer.querySelectorAll(".botMessage"); botMessages.forEach((botMessage) => { const element = botMessage; element.style.backgroundColor = hexValue; }); } await plugin.saveSettings(); }); }); new import_obsidian10.Setting(settingsContainer).setName("Chatbox Font Color").setDesc("Modify the font color of the chatbox.").addButton( (button) => button.setButtonText("Restore Default").setIcon("rotate-cw").setClass("clickable-icon").onClick(async () => { const defaultValue = colorToHex(defaultChatBoxFontColor); colorPicker7.setValue(defaultValue); const textarea = document.querySelector(".chatbox textarea"); if (textarea) { textarea.style.color = defaultValue; const style = document.createElement("style"); style.textContent = ` .chatbox textarea::placeholder { color: ${defaultValue} !important; } `; textarea.appendChild(style); await plugin.saveSettings(); } }) ).addColorPicker(async (color) => { colorPicker7 = color; let defaultValue = plugin.settings.appearance.chatBoxFontColor; if (defaultValue == "--text-normal") { defaultValue = colorToHex(defaultChatBoxFontColor); } color.setValue(defaultValue).onChange(async (value) => { const hexValue = colorToHex(value); plugin.settings.appearance.chatBoxFontColor = hexValue; const textarea = document.querySelector(".chatbox textarea"); if (textarea) { textarea.style.color = hexValue; const style = document.createElement("style"); style.textContent = ` .chatbox textarea::placeholder { color: ${hexValue} !important; } `; textarea.appendChild(style); } await plugin.saveSettings(); }); }); new import_obsidian10.Setting(settingsContainer).setName("Chatbox Background Color").setDesc("Modify the background color of the chatbox.").addButton( (button) => button.setButtonText("Restore Default").setIcon("rotate-cw").setClass("clickable-icon").onClick(async () => { const defaultValue = colorToHex(defaultChatBoxBackgroundColor); colorPicker8.setValue(defaultValue); const chatbox = document.querySelector(".chatbox"); if (chatbox) { const element = chatbox; element.style.backgroundColor = defaultValue; element.style.borderColor = defaultValue; await plugin.saveSettings(); } }) ).addColorPicker(async (color) => { colorPicker8 = color; let defaultValue = plugin.settings.appearance.chatBoxBackgroundColor; if (defaultValue == "--interactive-accent") { defaultValue = colorToHex(defaultChatBoxBackgroundColor); } color.setValue(defaultValue).onChange(async (value) => { const hexValue = colorToHex(value); plugin.settings.appearance.chatBoxBackgroundColor = hexValue; const chatbox = document.querySelector(".chatbox"); if (chatbox) { const element = chatbox; element.style.backgroundColor = hexValue; element.style.borderColor = hexValue; } const textarea = document.querySelector(".chatbox textarea"); if (textarea) { const element = textarea; element.style.backgroundColor = hexValue; element.style.borderColor = hexValue; } const submitButton = document.querySelector(".chatbox .submit-button"); if (submitButton) { const element = submitButton; element.style.backgroundColor = hexValue; element.style.borderColor = hexValue; } await plugin.saveSettings(); }); }); new import_obsidian10.Setting(settingsContainer).setName("Enable Scrollbar").setDesc("Display scrollbar in chatbox.").addToggle( (toggle) => toggle.setValue(plugin.settings.appearance.enableScrollBar).onChange((value) => { plugin.settings.appearance.enableScrollBar = value; if (value === true) { const chatbox = document.querySelector(".chatbox textarea"); if (chatbox) { chatbox.style.overflowY = "auto"; } } else { const chatbox = document.querySelector(".chatbox textarea"); if (chatbox) { chatbox.style.overflowY = "hidden"; } } plugin.saveSettings(); }) ); settingsContainer.createEl("h6", { text: "Generate View" }); let colorPicker9; let colorPicker10; const defaultBMOGenerateFontColor = getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.bmoGenerateFontColor).trim(); new import_obsidian10.Setting(settingsContainer).setName("BMO Generate Background Color").setDesc("Modify the background color of BMO Generate.").addButton( (button) => button.setButtonText("Restore Default").setIcon("rotate-cw").setClass("clickable-icon").onClick(async () => { colorPicker9.setValue(DEFAULT_SETTINGS.appearance.bmoGenerateBackgroundColor); const containers = document.querySelectorAll(".bmoCodeBlockContainer"); containers.forEach((container) => { const element = container; element.style.backgroundColor = DEFAULT_SETTINGS.appearance.bmoGenerateBackgroundColor; }); await plugin.saveSettings(); }) ).addColorPicker(async (color) => { colorPicker9 = color; const defaultValue = plugin.settings.appearance.bmoGenerateBackgroundColor; color.setValue(defaultValue).onChange(async (value) => { const hexValue = colorToHex(value); plugin.settings.appearance.bmoGenerateBackgroundColor = hexValue; const containers = document.querySelectorAll(".bmoCodeBlockContainer"); containers.forEach((container) => { const element = container; element.style.backgroundColor = hexValue; }); await plugin.saveSettings(); }); }); new import_obsidian10.Setting(settingsContainer).setName("BMO Generate Font Color").setDesc("Modify the font color of BMO Generate.").addButton( (button) => button.setButtonText("Restore Default").setIcon("rotate-cw").setClass("clickable-icon").onClick(async () => { const defaultValue = colorToHex(defaultBMOGenerateFontColor); colorPicker10.setValue(defaultValue); const bmoCodeBlockContents = document.querySelectorAll(".bmoCodeBlockContent"); bmoCodeBlockContents.forEach((content) => { const element = content; element.style.color = defaultValue; }); await plugin.saveSettings(); }) ).addColorPicker(async (color) => { colorPicker10 = color; let defaultValue = plugin.settings.appearance.bmoGenerateFontColor; if (defaultValue == "--text-normal") { defaultValue = colorToHex(defaultBMOGenerateFontColor); } color.setValue(defaultValue).onChange(async (value) => { const hexValue = colorToHex(value); plugin.settings.appearance.bmoGenerateFontColor = hexValue; const bmoCodeBlockContents2 = document.querySelectorAll(".bmoCodeBlockContent"); bmoCodeBlockContents2.forEach((content) => { const element = content; element.style.color = hexValue; }); await plugin.saveSettings(); }); const bmoCodeBlockContents = document.querySelectorAll(".bmoCodeBlockContent"); bmoCodeBlockContents.forEach((content) => { const element = content; element.style.color = defaultValue; }); }); } // src/components/settings/ChatHistorySettings.ts var import_obsidian11 = require("obsidian"); function addChatHistorySettings(containerEl, plugin, SettingTab15) { const toggleSettingContainer = containerEl.createDiv({ cls: "toggleSettingContainer" }); toggleSettingContainer.createEl("h2", { text: "Chat History" }); const initialState = plugin.settings.toggleChatHistorySettings; const chevronIcon = toggleSettingContainer.createEl("span", { cls: "chevron-icon" }); (0, import_obsidian11.setIcon)(chevronIcon, initialState ? "chevron-down" : "chevron-right"); const settingsContainer = containerEl.createDiv({ cls: "settingsContainer" }); settingsContainer.style.display = initialState ? "block" : "none"; toggleSettingContainer.addEventListener("click", async () => { const isOpen = settingsContainer.style.display !== "none"; if (isOpen) { (0, import_obsidian11.setIcon)(chevronIcon, "chevron-right"); settingsContainer.style.display = "none"; plugin.settings.toggleChatHistorySettings = false; } else { (0, import_obsidian11.setIcon)(chevronIcon, "chevron-down"); settingsContainer.style.display = "block"; plugin.settings.toggleChatHistorySettings = true; } await plugin.saveSettings(); }); new import_obsidian11.Setting(settingsContainer).setName("Chat History Folder Path").setDesc("Save your chat history in a specified folder.").addText( (text) => text.setPlaceholder("BMO/History").setValue(plugin.settings.chatHistory.chatHistoryPath || DEFAULT_SETTINGS.chatHistory.chatHistoryPath).onChange(async (value) => { plugin.settings.chatHistory.chatHistoryPath = value ? value : DEFAULT_SETTINGS.chatHistory.chatHistoryPath; if (value) { let folderPath = plugin.settings.chatHistory.chatHistoryPath.trim() || DEFAULT_SETTINGS.chatHistory.chatHistoryPath; while (folderPath.endsWith("/")) { folderPath = folderPath.substring(0, folderPath.length - 1); plugin.settings.chatHistory.chatHistoryPath = folderPath; } const folder = plugin.app.vault.getAbstractFileByPath(folderPath); if (folder && folder instanceof import_obsidian11.TFolder) { text.inputEl.style.borderColor = ""; } else { text.inputEl.style.borderColor = "red"; } } await plugin.saveSettings(); }).inputEl.addEventListener("focusout", async () => { SettingTab15.display(); }) ); new import_obsidian11.Setting(settingsContainer).setName("Template File Path").setDesc("Insert your template file path.").addText( (text) => text.setPlaceholder("templates/bmo.md").setValue(plugin.settings.chatHistory.templateFilePath || DEFAULT_SETTINGS.chatHistory.templateFilePath).onChange(async (value) => { plugin.settings.chatHistory.templateFilePath = value ? value : DEFAULT_SETTINGS.chatHistory.templateFilePath; if (value) { if (!plugin.settings.chatHistory.templateFilePath.endsWith(".md")) { plugin.settings.chatHistory.templateFilePath += ".md"; } await plugin.saveSettings(); const allFiles = plugin.app.vault.getFiles(); const fileExists = allFiles.some((file) => file.path.toLowerCase() === plugin.settings.chatHistory.templateFilePath.toLowerCase()); if (fileExists) { text.inputEl.style.borderColor = ""; } else { text.inputEl.style.borderColor = "red"; } } else { text.inputEl.style.borderColor = ""; plugin.settings.chatHistory.templateFilePath = DEFAULT_SETTINGS.chatHistory.templateFilePath; } }) ); new import_obsidian11.Setting(settingsContainer).setName("Enable Rename Note Title").setDesc("Enable model to rename the note title when saving chat history.").addToggle( (toggle) => toggle.setValue(plugin.settings.chatHistory.allowRenameNoteTitle).onChange((value) => { plugin.settings.chatHistory.allowRenameNoteTitle = value; plugin.saveSettings(); }) ); } // src/components/settings/OllamaSettings.ts var import_obsidian12 = require("obsidian"); // src/utils/DescriptionLink.ts function addDescriptionLink(text, link, extraWords, innerText) { const frag = new DocumentFragment(); const desc = document.createElement("span"); desc.innerText = text + " "; frag.appendChild(desc); const anchor = document.createElement("a"); anchor.href = link; anchor.target = "_blank"; anchor.rel = "noopener noreferrer"; anchor.innerText = innerText; frag.appendChild(anchor); const extra = document.createElement("span"); extra.innerText = " " + extraWords; frag.appendChild(extra); return frag; } // src/components/settings/OllamaSettings.ts function addOllamaSettings(containerEl, plugin, SettingTab15) { const toggleSettingContainer = containerEl.createDiv({ cls: "toggleSettingContainer" }); toggleSettingContainer.createEl("h2", { text: "Ollama Connection" }); const initialState = plugin.settings.toggleOllamaSettings; const chevronIcon = toggleSettingContainer.createEl("span", { cls: "chevron-icon" }); (0, import_obsidian12.setIcon)(chevronIcon, initialState ? "chevron-down" : "chevron-right"); const settingsContainer = containerEl.createDiv({ cls: "settingsContainer" }); settingsContainer.style.display = initialState ? "block" : "none"; toggleSettingContainer.addEventListener("click", async () => { const isOpen = settingsContainer.style.display !== "none"; if (isOpen) { (0, import_obsidian12.setIcon)(chevronIcon, "chevron-right"); settingsContainer.style.display = "none"; plugin.settings.toggleOllamaSettings = false; } else { (0, import_obsidian12.setIcon)(chevronIcon, "chevron-down"); settingsContainer.style.display = "block"; plugin.settings.toggleOllamaSettings = true; } await plugin.saveSettings(); }); new import_obsidian12.Setting(settingsContainer).setName("OLLAMA REST API URL").setDesc(addDescriptionLink("Enter your REST API URL. Update ", "https://ollama.com/", "to version >=0.1.42 to avoid CORS restriction.", "Ollama")).addText( (text) => text.setPlaceholder("http://localhost:11434").setValue(plugin.settings.OllamaConnection.RESTAPIURL || DEFAULT_SETTINGS.OllamaConnection.RESTAPIURL).onChange(async (value) => { plugin.settings.OllamaConnection.ollamaModels = []; plugin.settings.OllamaConnection.RESTAPIURL = value ? value : DEFAULT_SETTINGS.OllamaConnection.RESTAPIURL; if (plugin.settings.OllamaConnection.RESTAPIURL === "") { plugin.settings.OllamaConnection.ollamaModels = []; } else { const models = await fetchOllamaModels(plugin); models == null ? void 0 : models.forEach((model) => { if (!plugin.settings.OllamaConnection.ollamaModels.includes(model)) { plugin.settings.OllamaConnection.ollamaModels.push(model); } }); } }).inputEl.addEventListener("focusout", async () => { await plugin.saveSettings(); SettingTab15.display(); }) ); new import_obsidian12.Setting(settingsContainer).setName("Enable Stream").setDesc("Enable Ollama models to stream response.").addToggle( (toggle) => toggle.setValue(plugin.settings.OllamaConnection.enableStream).onChange((value) => { plugin.settings.OllamaConnection.enableStream = value; plugin.saveSettings(); }) ); const advancedToggleSettingContainer = settingsContainer.createDiv({ cls: "toggleSettingContainer" }); advancedToggleSettingContainer.createEl("h2", { text: "Advanced Settings" }); const advancedInitialState = plugin.settings.toggleAdvancedSettings; const advancedChevronIcon = advancedToggleSettingContainer.createEl("span", { cls: "chevron-icon" }); (0, import_obsidian12.setIcon)(advancedChevronIcon, advancedInitialState ? "chevron-down" : "chevron-right"); const advancedSettingsContainer = settingsContainer.createDiv({ cls: "settingsContainer" }); advancedSettingsContainer.style.display = advancedInitialState ? "block" : "none"; advancedToggleSettingContainer.addEventListener("click", async () => { const isOpen = advancedSettingsContainer.style.display !== "none"; if (isOpen) { (0, import_obsidian12.setIcon)(advancedChevronIcon, "chevron-right"); advancedSettingsContainer.style.display = "none"; plugin.settings.toggleAdvancedSettings = false; } else { (0, import_obsidian12.setIcon)(advancedChevronIcon, "chevron-down"); advancedSettingsContainer.style.display = "block"; plugin.settings.toggleAdvancedSettings = true; } await plugin.saveSettings(); }); new import_obsidian12.Setting(advancedSettingsContainer).setName("mirostat").setDesc("Enable Mirostat sampling for controlling perplexity. (default: 0, 0 = disabled, 1 = Mirostat, 2 = Mirostat 2.0)").addText( (text) => text.setPlaceholder("0").setValue(plugin.settings.OllamaConnection.ollamaParameters.mirostat || DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.mirostat).onChange(async (value) => { const intValue = parseInt(value, 10); if (isNaN(intValue)) { plugin.settings.OllamaConnection.ollamaParameters.mirostat = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.mirostat; } else { plugin.settings.OllamaConnection.ollamaParameters.mirostat = intValue.toString(); } await plugin.saveSettings(); }).inputEl.addEventListener("focusout", async () => { SettingTab15.display(); }) ); new import_obsidian12.Setting(advancedSettingsContainer).setName("mirostat_eta").setDesc("Influences how quickly the algorithm responds to feedback from the generated text. A lower learning rate will result in slower adjustments, while a higher learning rate will make the algorithm more responsive. (Default: 0.1)").addText( (text) => text.setPlaceholder("0.1").setValue(plugin.settings.OllamaConnection.ollamaParameters.mirostat_eta || DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.mirostat_eta).onChange(async (value) => { const floatValue = parseFloat(value); if (!isNaN(floatValue)) { plugin.settings.OllamaConnection.ollamaParameters.mirostat_eta = floatValue.toFixed(2).toString(); } else { plugin.settings.OllamaConnection.ollamaParameters.mirostat_eta = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.mirostat_eta; } await plugin.saveSettings(); }).inputEl.addEventListener("focusout", async () => { SettingTab15.display(); }) ); new import_obsidian12.Setting(advancedSettingsContainer).setName("mirostat_tau").setDesc("Controls the balance between coherence and diversity of the output. A lower value will result in more focused and coherent text. (Default: 5.0)").addText( (text) => text.setPlaceholder("5.00").setValue(plugin.settings.OllamaConnection.ollamaParameters.mirostat_tau || DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.mirostat_tau).onChange(async (value) => { const floatValue = parseFloat(value); if (!isNaN(floatValue)) { plugin.settings.OllamaConnection.ollamaParameters.mirostat_tau = floatValue.toFixed(2).toString(); } else { plugin.settings.OllamaConnection.ollamaParameters.mirostat_tau = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.mirostat_tau; } await plugin.saveSettings(); }).inputEl.addEventListener("focusout", async () => { SettingTab15.display(); }) ); new import_obsidian12.Setting(advancedSettingsContainer).setName("num_ctx").setDesc("Sets the size of the context window used to generate the next token. (Default: 2048)").addText( (text) => text.setPlaceholder("2048").setValue(plugin.settings.OllamaConnection.ollamaParameters.num_ctx || DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.num_ctx).onChange(async (value) => { const intValue = parseInt(value, 10); if (isNaN(intValue)) { plugin.settings.OllamaConnection.ollamaParameters.num_ctx = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.num_ctx; } else { plugin.settings.OllamaConnection.ollamaParameters.num_ctx = intValue.toString(); } await plugin.saveSettings(); }).inputEl.addEventListener("focusout", async () => { SettingTab15.display(); }) ); new import_obsidian12.Setting(advancedSettingsContainer).setName("num_gqa").setDesc("The number of GQA groups in the transformer layer. Required for some models, for example it is 8 for llama2:70b.").addText( (text) => text.setPlaceholder("0").setValue(plugin.settings.OllamaConnection.ollamaParameters.num_gqa || DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.num_gqa).onChange(async (value) => { const intValue = parseInt(value, 10); if (isNaN(intValue)) { plugin.settings.OllamaConnection.ollamaParameters.num_gqa = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.num_gqa; } else { plugin.settings.OllamaConnection.ollamaParameters.num_gqa = intValue.toString(); } await plugin.saveSettings(); }).inputEl.addEventListener("focusout", async () => { SettingTab15.display(); }) ); new import_obsidian12.Setting(advancedSettingsContainer).setName("num_thread").setDesc("Sets the number of threads to use during computation. By default, Ollama will detect this for optimal performance. It is recommended to set this value to the number of physical CPU cores your system has (as opposed to the logical number of cores).").addText( (text) => text.setPlaceholder("0").setValue(plugin.settings.OllamaConnection.ollamaParameters.num_thread || DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.num_thread).onChange(async (value) => { const intValue = parseInt(value, 10); if (isNaN(intValue)) { plugin.settings.OllamaConnection.ollamaParameters.num_thread = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.num_thread; } else { plugin.settings.OllamaConnection.ollamaParameters.num_thread = intValue.toString(); } await plugin.saveSettings(); }).inputEl.addEventListener("focusout", async () => { SettingTab15.display(); }) ); new import_obsidian12.Setting(advancedSettingsContainer).setName("repeat_last_n").setDesc("Sets how far back for the model to look back to prevent repetition. (Default: 64, 0 = disabled, -1 = num_ctx)").addText( (text) => text.setPlaceholder("64").setValue(plugin.settings.OllamaConnection.ollamaParameters.repeat_last_n || DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.repeat_last_n).onChange(async (value) => { const intValue = parseInt(value, 10); if (isNaN(intValue)) { plugin.settings.OllamaConnection.ollamaParameters.repeat_last_n = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.repeat_last_n; } else { plugin.settings.OllamaConnection.ollamaParameters.repeat_last_n = intValue.toString(); } await plugin.saveSettings(); }).inputEl.addEventListener("focusout", async () => { SettingTab15.display(); }) ); new import_obsidian12.Setting(advancedSettingsContainer).setName("repeat_penalty").setDesc("Sets how strongly to penalize repetitions. A higher value (e.g., 1.5) will penalize repetitions more strongly, while a lower value (e.g., 0.9) will be more lenient. (Default: 1.1)").addText( (text) => text.setPlaceholder("1.1").setValue(plugin.settings.OllamaConnection.ollamaParameters.repeat_penalty || DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.repeat_penalty).onChange(async (value) => { const floatValue = parseFloat(value); if (isNaN(floatValue)) { plugin.settings.OllamaConnection.ollamaParameters.repeat_penalty = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.repeat_penalty; } else { plugin.settings.OllamaConnection.ollamaParameters.repeat_penalty = floatValue.toString(); } await plugin.saveSettings(); }).inputEl.addEventListener("focusout", async () => { SettingTab15.display(); }) ); new import_obsidian12.Setting(advancedSettingsContainer).setName("seed").setDesc("Sets the random number seed to use for generation. Setting this to a specific number will make the model generate the same text for the same prompt.").addText( (text) => text.setPlaceholder("0").setValue(plugin.settings.OllamaConnection.ollamaParameters.seed || DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.seed).onChange(async (value) => { const intValue = parseInt(value, 10); if (isNaN(intValue)) { plugin.settings.OllamaConnection.ollamaParameters.seed = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.seed; } else { plugin.settings.OllamaConnection.ollamaParameters.seed = intValue.toString(); } await plugin.saveSettings(); }).inputEl.addEventListener("focusout", async () => { SettingTab15.display(); }) ); new import_obsidian12.Setting(advancedSettingsContainer).setName("stop").setDesc("Sets the stop sequences to use. When this pattern is encountered, the LLM will stop generating text and return. Multiple stop patterns may be set by specifying them as a comma-separated list in the input field.").addText( (text) => text.setPlaceholder("stop, \\n, user:").setValue(plugin.settings.OllamaConnection.ollamaParameters.stop && Array.isArray(plugin.settings.OllamaConnection.ollamaParameters.stop) ? plugin.settings.OllamaConnection.ollamaParameters.stop.join(", ") : DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.stop.join(", ")).onChange(async (value) => { const stopsArray = value ? value.split(",").map((s) => s.trim()) : [...DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.stop]; plugin.settings.OllamaConnection.ollamaParameters.stop = stopsArray; await plugin.saveSettings(); }).inputEl.addEventListener("focusout", async () => { SettingTab15.display(); }) ); new import_obsidian12.Setting(advancedSettingsContainer).setName("tfs_z").setDesc("Tail free sampling is used to reduce the impact of less probable tokens from the output. A higher value (e.g., 2.0) will reduce the impact more, while a value of 1.0 disables this setting. (default: 1)").addText( (text) => text.setPlaceholder("1.0").setValue(plugin.settings.OllamaConnection.ollamaParameters.tfs_z || DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.tfs_z).onChange(async (value) => { const floatValue = parseFloat(value); if (isNaN(floatValue)) { plugin.settings.OllamaConnection.ollamaParameters.tfs_z = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.tfs_z; } else { plugin.settings.OllamaConnection.ollamaParameters.tfs_z = floatValue.toFixed(2).toString(); } await plugin.saveSettings(); }).inputEl.addEventListener("focusout", async () => { SettingTab15.display(); }) ); new import_obsidian12.Setting(advancedSettingsContainer).setName("top_k").setDesc("Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40)").addText( (text) => text.setPlaceholder("40").setValue(plugin.settings.OllamaConnection.ollamaParameters.top_k || DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.top_k).onChange(async (value) => { const intValue = parseInt(value, 10); if (isNaN(intValue)) { plugin.settings.OllamaConnection.ollamaParameters.top_k = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.top_k; } else { plugin.settings.OllamaConnection.ollamaParameters.top_k = intValue.toString(); } await plugin.saveSettings(); }).inputEl.addEventListener("focusout", async () => { SettingTab15.display(); }) ); new import_obsidian12.Setting(advancedSettingsContainer).setName("top_p").setDesc("Works together with top-k. A higher value (e.g., 0.95) will lead to more diverse text, while a lower value (e.g., 0.5) will generate more focused and conservative text. (Default: 0.9)").addText( (text) => text.setPlaceholder("1.0").setValue(plugin.settings.OllamaConnection.ollamaParameters.top_p || DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.top_p).onChange(async (value) => { const floatValue = parseFloat(value); if (isNaN(floatValue)) { plugin.settings.OllamaConnection.ollamaParameters.top_p = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.top_p; } else { plugin.settings.OllamaConnection.ollamaParameters.top_p = floatValue.toFixed(2).toString(); } await plugin.saveSettings(); }).inputEl.addEventListener("focusout", async () => { SettingTab15.display(); }) ); new import_obsidian12.Setting(advancedSettingsContainer).setName("min_p").setDesc("Alternative to the top_p, and aims to ensure a balance of quality and variety. The parameter p represents the minimum probability for a token to be considered, relative to the probability of the most likely token. (Default: 0.0)").addText( (text) => text.setPlaceholder("0.0").setValue(plugin.settings.OllamaConnection.ollamaParameters.min_p || DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.min_p).onChange(async (value) => { const floatValue = parseFloat(value); if (isNaN(floatValue)) { plugin.settings.OllamaConnection.ollamaParameters.min_p = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.min_p; } else { plugin.settings.OllamaConnection.ollamaParameters.min_p = floatValue.toFixed(2).toString(); } await plugin.saveSettings(); }).inputEl.addEventListener("focusout", async () => { SettingTab15.display(); }) ); new import_obsidian12.Setting(advancedSettingsContainer).setName("keep_alive").setDesc("If set to a positive duration (e.g. 20m, 1hr or 30), the model will stay loaded for the provided duration in seconds. If set to a negative duration (e.g. -1), the model will stay loaded indefinitely. If set to 0, the model will be unloaded immediately once finished. If not set, the model will stay loaded for 5 minutes by default.").addText( (text) => text.setPlaceholder("30s").setValue(plugin.settings.OllamaConnection.ollamaParameters.keep_alive || DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.keep_alive).onChange(async (value) => { const match = value.match(/^(-?\d+)(m|hr|h)?$/); if (match) { const num = parseInt(match[1]); const unit = match[2]; let seconds; if (unit === "m") { seconds = num * 60; } else if (unit === "hr" || unit === "h") { seconds = num * 3600; } else { seconds = num; } plugin.settings.OllamaConnection.ollamaParameters.keep_alive = seconds.toString(); } else { plugin.settings.OllamaConnection.ollamaParameters.keep_alive = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.keep_alive; } await plugin.saveSettings(); }).inputEl.addEventListener("focusout", async () => { SettingTab15.display(); }) ); } // src/components/settings/ConnectionSettings.ts var import_obsidian18 = require("obsidian"); // src/components/settings/APIConnections/OpenAIConnections.ts var import_obsidian13 = require("obsidian"); function addOpenAIConnectionSettings(containerEl, plugin, SettingTab15) { const toggleSettingContainer = containerEl.createDiv({ cls: "toggleSettingContainer" }); toggleSettingContainer.createEl("h2", { text: "OpenAI" }); const initialState = plugin.settings.toggleOpenAISettings; const chevronIcon = toggleSettingContainer.createEl("span", { cls: "chevron-icon" }); (0, import_obsidian13.setIcon)(chevronIcon, initialState ? "chevron-down" : "chevron-right"); const settingsContainer = containerEl.createDiv({ cls: "settingsContainer" }); settingsContainer.style.display = initialState ? "block" : "none"; toggleSettingContainer.addEventListener("click", async () => { const isOpen = settingsContainer.style.display !== "none"; if (isOpen) { (0, import_obsidian13.setIcon)(chevronIcon, "chevron-right"); settingsContainer.style.display = "none"; plugin.settings.toggleOpenAISettings = false; } else { (0, import_obsidian13.setIcon)(chevronIcon, "chevron-down"); settingsContainer.style.display = "block"; plugin.settings.toggleOpenAISettings = true; } await plugin.saveSettings(); }); new import_obsidian13.Setting(settingsContainer).setName("OpenAI API Key").setDesc("Insert OpenAI API Key.").addText( (text) => text.setPlaceholder("insert-api-key").setValue(plugin.settings.APIConnections.openAI.APIKey ? `${plugin.settings.APIConnections.openAI.APIKey.slice(0, 7)}-...${plugin.settings.APIConnections.openAI.APIKey.slice(-4)}` : "").onChange(async (value) => { plugin.settings.APIConnections.openAI.openAIBaseModels = []; plugin.settings.APIConnections.openAI.APIKey = value; if (plugin.settings.APIConnections.openAI.APIKey === "") { plugin.settings.APIConnections.openAI.openAIBaseModels = []; } else { const models = await fetchOpenAIBaseModels(plugin); models.forEach((model) => { if (!plugin.settings.APIConnections.openAI.openAIBaseModels.includes(model)) { plugin.settings.APIConnections.openAI.openAIBaseModels.push(model); } }); } }).inputEl.addEventListener("focusout", async () => { await plugin.saveSettings(); SettingTab15.display(); }) ); new import_obsidian13.Setting(settingsContainer).setName("OpenAI-Based URL").setDesc("Enter your custom OpenAI-Based URL.").addButton( (button) => button.setButtonText("Restore Default").setIcon("rotate-cw").setClass("clickable-icon").onClick(async () => { plugin.settings.APIConnections.openAI.openAIBaseModels = []; plugin.settings.APIConnections.openAI.openAIBaseUrl = DEFAULT_SETTINGS.APIConnections.openAI.openAIBaseUrl; await plugin.saveSettings(); SettingTab15.display(); }) ).addText( (text) => text.setPlaceholder("https://api.openai.com/v1").setValue(plugin.settings.APIConnections.openAI.openAIBaseUrl || DEFAULT_SETTINGS.APIConnections.openAI.openAIBaseUrl).onChange(async (value) => { plugin.settings.APIConnections.openAI.openAIBaseUrl = value ? value : DEFAULT_SETTINGS.APIConnections.openAI.openAIBaseUrl; await plugin.saveSettings(); }).inputEl.addEventListener("focusout", async () => { SettingTab15.display(); }) ); new import_obsidian13.Setting(settingsContainer).setName("Enable Stream").setDesc("Enable stream for OpenAI-Based models.").addToggle( (toggle) => toggle.setValue(plugin.settings.APIConnections.openAI.enableStream).onChange(async (value) => { plugin.settings.APIConnections.openAI.enableStream = value; await plugin.saveSettings(); }) ); } // src/components/settings/APIConnections/MistralConnections.ts var import_obsidian14 = require("obsidian"); function addMistralConnectionSettings(containerEl, plugin, SettingTab15) { const toggleSettingContainer = containerEl.createDiv({ cls: "toggleSettingContainer" }); toggleSettingContainer.createEl("h2", { text: "Mistral AI" }); const initialState = plugin.settings.toggleMistralSettings; const chevronIcon = toggleSettingContainer.createEl("span", { cls: "chevron-icon" }); (0, import_obsidian14.setIcon)(chevronIcon, initialState ? "chevron-down" : "chevron-right"); const settingsContainer = containerEl.createDiv({ cls: "settingsContainer" }); settingsContainer.style.display = initialState ? "block" : "none"; toggleSettingContainer.addEventListener("click", async () => { const isOpen = settingsContainer.style.display !== "none"; if (isOpen) { (0, import_obsidian14.setIcon)(chevronIcon, "chevron-right"); settingsContainer.style.display = "none"; plugin.settings.toggleMistralSettings = false; } else { (0, import_obsidian14.setIcon)(chevronIcon, "chevron-down"); settingsContainer.style.display = "block"; plugin.settings.toggleMistralSettings = true; } await plugin.saveSettings(); }); new import_obsidian14.Setting(settingsContainer).setName("Mistral API Key").setDesc("Insert Mistral API Key.").addText( (text) => text.setPlaceholder("insert-api-key").setValue(plugin.settings.APIConnections.mistral.APIKey ? `${plugin.settings.APIConnections.mistral.APIKey.slice(0, 6)}-...${plugin.settings.APIConnections.mistral.APIKey.slice(-4)}` : "").onChange(async (value) => { plugin.settings.APIConnections.mistral.mistralModels = []; plugin.settings.APIConnections.mistral.APIKey = value; if (plugin.settings.APIConnections.mistral.APIKey === "") { plugin.settings.APIConnections.mistral.mistralModels = []; } else { const models = await fetchMistralModels(plugin); models.forEach((model) => { if (!plugin.settings.APIConnections.mistral.mistralModels.includes(model)) { plugin.settings.APIConnections.mistral.mistralModels.push(model); } }); } }).inputEl.addEventListener("focusout", async () => { await plugin.saveSettings(); SettingTab15.display(); }) ); new import_obsidian14.Setting(settingsContainer).setName("Enable Stream").setDesc("Enable stream for Mistral models.").addToggle( (toggle) => toggle.setValue(plugin.settings.APIConnections.mistral.enableStream).onChange((value) => { plugin.settings.APIConnections.mistral.enableStream = value; plugin.saveSettings(); }) ); } // src/components/settings/APIConnections/GoogleGeminiConnections.ts var import_obsidian15 = require("obsidian"); function addGoogleGeminiConnectionSettings(containerEl, plugin, SettingTab15) { const toggleSettingContainer = containerEl.createDiv({ cls: "toggleSettingContainer" }); toggleSettingContainer.createEl("h2", { text: "Google Gemini" }); const initialState = plugin.settings.toggleGoogleGeminiSettings; const chevronIcon = toggleSettingContainer.createEl("span", { cls: "chevron-icon" }); (0, import_obsidian15.setIcon)(chevronIcon, initialState ? "chevron-down" : "chevron-right"); const settingsContainer = containerEl.createDiv({ cls: "settingsContainer" }); settingsContainer.style.display = initialState ? "block" : "none"; toggleSettingContainer.addEventListener("click", async () => { const isOpen = settingsContainer.style.display !== "none"; if (isOpen) { (0, import_obsidian15.setIcon)(chevronIcon, "chevron-right"); settingsContainer.style.display = "none"; plugin.settings.toggleGoogleGeminiSettings = false; } else { (0, import_obsidian15.setIcon)(chevronIcon, "chevron-down"); settingsContainer.style.display = "block"; plugin.settings.toggleGoogleGeminiSettings = true; } await plugin.saveSettings(); }); new import_obsidian15.Setting(settingsContainer).setName("Google Gemini API Key").setDesc("Insert Google Gemini API Key.").addText( (text) => text.setPlaceholder("insert-api-key").setValue(plugin.settings.APIConnections.googleGemini.APIKey ? `${plugin.settings.APIConnections.googleGemini.APIKey.slice(0, 6)}-...${plugin.settings.APIConnections.googleGemini.APIKey.slice(-4)}` : "").onChange(async (value) => { plugin.settings.APIConnections.googleGemini.geminiModels = []; plugin.settings.APIConnections.googleGemini.APIKey = value; if (plugin.settings.APIConnections.googleGemini.APIKey === "") { plugin.settings.APIConnections.googleGemini.geminiModels = []; } else { const models = await fetchGoogleGeminiModels(plugin); models.forEach((model) => { if (!plugin.settings.APIConnections.googleGemini.geminiModels.includes(model)) { plugin.settings.APIConnections.googleGemini.geminiModels.push(model); } }); } }).inputEl.addEventListener("focusout", async () => { await plugin.saveSettings(); SettingTab15.display(); }) ); new import_obsidian15.Setting(settingsContainer).setName("Enable Stream").setDesc("Enable Google Gemini models to stream response.").addToggle( (toggle) => toggle.setValue(plugin.settings.APIConnections.googleGemini.enableStream).onChange((value) => { plugin.settings.APIConnections.googleGemini.enableStream = value; plugin.saveSettings(); }) ); } // src/components/settings/APIConnections/AnthropicConnections.ts var import_obsidian16 = require("obsidian"); function addAnthropicConnectionSettings(containerEl, plugin, SettingTab15) { const toggleSettingContainer = containerEl.createDiv({ cls: "toggleSettingContainer" }); toggleSettingContainer.createEl("h2", { text: "Anthropic" }); const initialState = plugin.settings.toggleAnthropicSettings; const chevronIcon = toggleSettingContainer.createEl("span", { cls: "chevron-icon" }); (0, import_obsidian16.setIcon)(chevronIcon, initialState ? "chevron-down" : "chevron-right"); const settingsContainer = containerEl.createDiv({ cls: "settingsContainer" }); settingsContainer.style.display = initialState ? "block" : "none"; toggleSettingContainer.addEventListener("click", async () => { const isOpen = settingsContainer.style.display !== "none"; if (isOpen) { (0, import_obsidian16.setIcon)(chevronIcon, "chevron-right"); settingsContainer.style.display = "none"; plugin.settings.toggleAnthropicSettings = false; } else { (0, import_obsidian16.setIcon)(chevronIcon, "chevron-down"); settingsContainer.style.display = "block"; plugin.settings.toggleAnthropicSettings = true; } await plugin.saveSettings(); }); new import_obsidian16.Setting(settingsContainer).setName("Anthropic API Key").setDesc("Insert Anthropic API Key. Warning: Anthropic models cannot be aborted. Please use with caution.").addText( (text) => text.setPlaceholder("insert-api-key").setValue(plugin.settings.APIConnections.anthropic.APIKey ? `${plugin.settings.APIConnections.anthropic.APIKey.slice(0, 6)}-...${plugin.settings.APIConnections.anthropic.APIKey.slice(-4)}` : "").onChange(async (value) => { plugin.settings.APIConnections.anthropic.anthropicModels = []; plugin.settings.APIConnections.anthropic.APIKey = value; if (plugin.settings.APIConnections.anthropic.APIKey === "") { plugin.settings.APIConnections.anthropic.anthropicModels = []; } else { const models = ANTHROPIC_MODELS; models.forEach((model) => { if (!plugin.settings.APIConnections.anthropic.anthropicModels.includes(model)) { plugin.settings.APIConnections.anthropic.anthropicModels.push(model); } }); } }).inputEl.addEventListener("focusout", async () => { await plugin.saveSettings(); SettingTab15.display(); }) ); } // src/components/settings/APIConnections/OpenRouterConnections.ts var import_obsidian17 = require("obsidian"); function addOpenRouterConnectionSettings(containerEl, plugin, SettingTab15) { const toggleSettingContainer = containerEl.createDiv({ cls: "toggleSettingContainer" }); toggleSettingContainer.createEl("h2", { text: "OpenRouter" }); const initialState = plugin.settings.toggleOpenRouterSettings; const chevronIcon = toggleSettingContainer.createEl("span", { cls: "chevron-icon" }); (0, import_obsidian17.setIcon)(chevronIcon, initialState ? "chevron-down" : "chevron-right"); const settingsContainer = containerEl.createDiv({ cls: "settingsContainer" }); settingsContainer.style.display = initialState ? "block" : "none"; toggleSettingContainer.addEventListener("click", async () => { const isOpen = settingsContainer.style.display !== "none"; if (isOpen) { (0, import_obsidian17.setIcon)(chevronIcon, "chevron-right"); settingsContainer.style.display = "none"; plugin.settings.toggleOpenRouterSettings = false; } else { (0, import_obsidian17.setIcon)(chevronIcon, "chevron-down"); settingsContainer.style.display = "block"; plugin.settings.toggleOpenRouterSettings = true; } await plugin.saveSettings(); }); new import_obsidian17.Setting(settingsContainer).setName("OpenRouter API Key").setDesc("Insert OpenRouter API Key.").addText( (text) => text.setPlaceholder("insert-api-key").setValue(plugin.settings.APIConnections.openRouter.APIKey ? `${plugin.settings.APIConnections.openRouter.APIKey.slice(0, 6)}-...${plugin.settings.APIConnections.openRouter.APIKey.slice(-4)}` : "").onChange(async (value) => { plugin.settings.APIConnections.openAI.openAIBaseModels = []; plugin.settings.APIConnections.openRouter.APIKey = value; if (plugin.settings.APIConnections.openRouter.APIKey === "") { plugin.settings.APIConnections.openRouter.openRouterModels = []; } else { const models = await fetchOpenRouterModels(plugin); models.forEach((model) => { if (!plugin.settings.APIConnections.openRouter.openRouterModels.includes(model)) { plugin.settings.APIConnections.openRouter.openRouterModels.push(model); } }); } }).inputEl.addEventListener("focusout", async () => { await plugin.saveSettings(); SettingTab15.display(); }) ); new import_obsidian17.Setting(settingsContainer).setName("Enable Stream").setDesc("Enable stream for OpenRouter models.").addToggle( (toggle) => toggle.setValue(plugin.settings.APIConnections.openRouter.enableStream).onChange((value) => { plugin.settings.APIConnections.openRouter.enableStream = value; plugin.saveSettings(); }) ); } // src/components/settings/ConnectionSettings.ts function addAPIConnectionSettings(containerEl, plugin, SettingTab15) { const toggleSettingContainer = containerEl.createDiv({ cls: "toggleSettingContainer" }); toggleSettingContainer.createEl("h2", { text: "API Connections" }); const initialState = plugin.settings.toggleAPIConnectionSettings; const chevronIcon = toggleSettingContainer.createEl("span", { cls: "chevron-icon" }); (0, import_obsidian18.setIcon)(chevronIcon, initialState ? "chevron-down" : "chevron-right"); const settingsContainer = containerEl.createDiv({ cls: "settingsContainer" }); settingsContainer.style.display = initialState ? "block" : "none"; toggleSettingContainer.addEventListener("click", async () => { const isOpen = settingsContainer.style.display !== "none"; if (isOpen) { (0, import_obsidian18.setIcon)(chevronIcon, "chevron-right"); settingsContainer.style.display = "none"; plugin.settings.toggleAPIConnectionSettings = false; } else { (0, import_obsidian18.setIcon)(chevronIcon, "chevron-down"); settingsContainer.style.display = "block"; plugin.settings.toggleAPIConnectionSettings = true; } await plugin.saveSettings(); }); addAnthropicConnectionSettings(settingsContainer, plugin, SettingTab15); addGoogleGeminiConnectionSettings(settingsContainer, plugin, SettingTab15); addMistralConnectionSettings(settingsContainer, plugin, SettingTab15); addOpenAIConnectionSettings(settingsContainer, plugin, SettingTab15); addOpenRouterConnectionSettings(settingsContainer, plugin, SettingTab15); } // src/components/settings/ProfileSettings.ts var import_obsidian19 = require("obsidian"); function addProfileSettings(containerEl, plugin, SettingTab15) { const toggleSettingContainer = containerEl.createDiv({ cls: "toggleSettingContainer" }); toggleSettingContainer.createEl("h2", { text: "Profiles" }); const initialState = plugin.settings.toggleProfileSettings; const chevronIcon = toggleSettingContainer.createEl("span", { cls: "chevron-icon" }); (0, import_obsidian19.setIcon)(chevronIcon, initialState ? "chevron-down" : "chevron-right"); const settingsContainer = containerEl.createDiv({ cls: "settingsContainer" }); settingsContainer.style.display = initialState ? "block" : "none"; toggleSettingContainer.addEventListener("click", async () => { const isOpen = settingsContainer.style.display !== "none"; if (isOpen) { (0, import_obsidian19.setIcon)(chevronIcon, "chevron-right"); settingsContainer.style.display = "none"; plugin.settings.toggleProfileSettings = false; } else { (0, import_obsidian19.setIcon)(chevronIcon, "chevron-down"); settingsContainer.style.display = "block"; plugin.settings.toggleProfileSettings = true; } await plugin.saveSettings(); }); new import_obsidian19.Setting(settingsContainer).setName("Profile").setDesc("Select a profile.").addDropdown((dropdown) => { if (plugin.settings.profiles.profileFolderPath !== "") { const files = plugin.app.vault.getFiles().filter((file) => file.path.startsWith(plugin.settings.profiles.profileFolderPath)); files.sort((a, b) => a.name.localeCompare(b.name)); const dataFolderPath = "./.obsidian/plugins/bmo-chatbot/data/"; if (!plugin.app.vault.getAbstractFileByPath(dataFolderPath)) { plugin.app.vault.adapter.mkdir(dataFolderPath); } files.forEach((file) => { if (file instanceof import_obsidian19.TFile) { const fileName = file.basename; const newFileName = `messageHistory_${fileName}.json`; const newFilePath = `${dataFolderPath}${newFileName}`; plugin.app.vault.create(newFilePath, "").catch((err) => { if (err.message === "File already exists.") { } else { throw err; } }); dropdown.addOption(file.name, fileName); } }); } dropdown.setValue(plugin.settings.profiles.profile || DEFAULT_SETTINGS.profiles.profile).onChange(async (value) => { plugin.settings.profiles.profile = value ? value : DEFAULT_SETTINGS.profiles.profile; const profileFilePath = plugin.settings.profiles.profileFolderPath + "/" + plugin.settings.profiles.profile; const currentProfile = plugin.app.vault.getAbstractFileByPath(profileFilePath); plugin.activateView(); await updateSettingsFromFrontMatter(plugin, currentProfile); await plugin.saveSettings(); SettingTab15.display(); }); }); new import_obsidian19.Setting(settingsContainer).setName("Profile Folder Path").setDesc("Select a profile from a specified folder.").addText( (text) => text.setPlaceholder("BMO/Profiles").setValue(plugin.settings.profiles.profileFolderPath || DEFAULT_SETTINGS.profiles.profileFolderPath).onChange(async (value) => { plugin.settings.profiles.profileFolderPath = value ? value : DEFAULT_SETTINGS.profiles.profileFolderPath; if (value) { let folderPath = plugin.settings.profiles.profileFolderPath.trim() || DEFAULT_SETTINGS.profiles.profileFolderPath; while (folderPath.endsWith("/")) { folderPath = folderPath.substring(0, folderPath.length - 1); plugin.settings.profiles.profileFolderPath = folderPath; } const folder = plugin.app.vault.getAbstractFileByPath(folderPath); if (folder && folder instanceof import_obsidian19.TFolder) { text.inputEl.style.borderColor = ""; } else { text.inputEl.style.borderColor = "red"; } } await plugin.saveSettings(); }).inputEl.addEventListener("focusout", async () => { SettingTab15.display(); }) ); } // src/components/settings/RESTAPIURLSettings.ts var import_obsidian20 = require("obsidian"); function addRESTAPIURLSettings(containerEl, plugin, SettingTab15) { const toggleSettingContainer = containerEl.createDiv({ cls: "toggleSettingContainer" }); toggleSettingContainer.createEl("h2", { text: "REST API Connection" }); const initialState = plugin.settings.toggleRESTAPIURLSettings; const chevronIcon = toggleSettingContainer.createEl("span", { cls: "chevron-icon" }); (0, import_obsidian20.setIcon)(chevronIcon, initialState ? "chevron-down" : "chevron-right"); const settingsContainer = containerEl.createDiv({ cls: "settingsContainer" }); settingsContainer.style.display = initialState ? "block" : "none"; toggleSettingContainer.addEventListener("click", async () => { const isOpen = settingsContainer.style.display !== "none"; if (isOpen) { (0, import_obsidian20.setIcon)(chevronIcon, "chevron-right"); settingsContainer.style.display = "none"; plugin.settings.toggleRESTAPIURLSettings = false; } else { (0, import_obsidian20.setIcon)(chevronIcon, "chevron-down"); settingsContainer.style.display = "block"; plugin.settings.toggleRESTAPIURLSettings = true; } await plugin.saveSettings(); }); new import_obsidian20.Setting(settingsContainer).setName("API Key").setDesc("Insert API Key (Optional).").addText( (text) => text.setPlaceholder("insert-api-key").setValue(plugin.settings.RESTAPIURLConnection.APIKey ? `${plugin.settings.RESTAPIURLConnection.APIKey.slice(0, 6)}-...${plugin.settings.RESTAPIURLConnection.APIKey.slice(-4)}` : "").onChange(async (value) => { plugin.settings.RESTAPIURLConnection.RESTAPIURLModels = []; plugin.settings.RESTAPIURLConnection.APIKey = value; await plugin.saveSettings(); }).inputEl.addEventListener("focusout", async () => { SettingTab15.display(); }) ); new import_obsidian20.Setting(settingsContainer).setName("REST API URL").setDesc(addDescriptionLink("ENTER YOUR REST API URL.", "https://github.com/longy2k/obsidian-bmo-chatbot/wiki/How-to-setup-with-LM-Studio", "", "[Instructions]")).addText( (text) => text.setPlaceholder("http://localhost:1234/v1").setValue(plugin.settings.RESTAPIURLConnection.RESTAPIURL || DEFAULT_SETTINGS.RESTAPIURLConnection.RESTAPIURL).onChange(async (value) => { plugin.settings.RESTAPIURLConnection.RESTAPIURLModels = []; plugin.settings.RESTAPIURLConnection.RESTAPIURL = value ? value : DEFAULT_SETTINGS.RESTAPIURLConnection.RESTAPIURL; if (plugin.settings.RESTAPIURLConnection.RESTAPIURL === "") { plugin.settings.RESTAPIURLConnection.RESTAPIURLModels = []; } else { const models = await fetchRESTAPIURLModels(plugin); models.forEach((model) => { if (!plugin.settings.RESTAPIURLConnection.RESTAPIURLModels.includes(model)) { plugin.settings.RESTAPIURLConnection.RESTAPIURLModels.push(model); } }); } }).inputEl.addEventListener("focusout", async () => { await plugin.saveSettings(); SettingTab15.display(); }) ); new import_obsidian20.Setting(settingsContainer).setName("Enable Stream").setDesc(addDescriptionLink("Enable REST API models to stream response.", "", "", "")).addToggle( (toggle) => toggle.setValue(plugin.settings.RESTAPIURLConnection.enableStream).onChange((value) => { plugin.settings.RESTAPIURLConnection.enableStream = value; plugin.saveSettings(); }) ); } // src/components/settings/EditorSettings.ts var import_obsidian21 = require("obsidian"); async function addEditorSettings(containerEl, plugin, SettingTab15) { const toggleSettingContainer = containerEl.createDiv({ cls: "toggleSettingContainer" }); toggleSettingContainer.createEl("h2", { text: "Editor" }); const initialState = plugin.settings.toggleEditorSettings; const chevronIcon = toggleSettingContainer.createEl("span", { cls: "chevron-icon" }); (0, import_obsidian21.setIcon)(chevronIcon, initialState ? "chevron-down" : "chevron-right"); const settingsContainer = containerEl.createDiv({ cls: "settingsContainer" }); settingsContainer.style.display = initialState ? "block" : "none"; toggleSettingContainer.addEventListener("click", async () => { const isOpen = settingsContainer.style.display !== "none"; if (isOpen) { (0, import_obsidian21.setIcon)(chevronIcon, "chevron-right"); settingsContainer.style.display = "none"; plugin.settings.toggleEditorSettings = false; } else { (0, import_obsidian21.setIcon)(chevronIcon, "chevron-down"); settingsContainer.style.display = "block"; plugin.settings.toggleEditorSettings = true; } await plugin.saveSettings(); }); new import_obsidian21.Setting(settingsContainer).setName("Editor System Role").setDesc("System role for BMO Generate and 'Prompt Select Generate' command.").addTextArea( (text) => text.setPlaceholder("You are a helpful assistant.").setValue(plugin.settings.editor.systen_role !== void 0 ? plugin.settings.editor.systen_role : DEFAULT_SETTINGS.editor.systen_role).onChange(async (value) => { plugin.settings.editor.systen_role = value !== void 0 ? value : DEFAULT_SETTINGS.editor.systen_role; await plugin.saveSettings(); }) ); } // src/components/settings/PromptSettings.ts var import_obsidian22 = require("obsidian"); function addPromptSettings(containerEl, plugin, SettingTab15) { const toggleSettingContainer = containerEl.createDiv({ cls: "toggleSettingContainer" }); toggleSettingContainer.createEl("h2", { text: "Prompts" }); const initialState = plugin.settings.togglePromptSettings; const chevronIcon = toggleSettingContainer.createEl("span", { cls: "chevron-icon" }); (0, import_obsidian22.setIcon)(chevronIcon, initialState ? "chevron-down" : "chevron-right"); const settingsContainer = containerEl.createDiv({ cls: "settingsContainer" }); settingsContainer.style.display = initialState ? "block" : "none"; toggleSettingContainer.addEventListener("click", async () => { const isOpen = settingsContainer.style.display !== "none"; if (isOpen) { (0, import_obsidian22.setIcon)(chevronIcon, "chevron-right"); settingsContainer.style.display = "none"; plugin.settings.togglePromptSettings = false; } else { (0, import_obsidian22.setIcon)(chevronIcon, "chevron-down"); settingsContainer.style.display = "block"; plugin.settings.togglePromptSettings = true; } await plugin.saveSettings(); }); new import_obsidian22.Setting(settingsContainer).setName("Prompt").setDesc("Select a prompt to provide additional context to the system role.").addDropdown((dropdown) => { dropdown.addOption("", "--EMPTY--"); if (plugin.settings.prompts.promptFolderPath !== "") { const files = plugin.app.vault.getFiles().filter((file) => file.path.startsWith(plugin.settings.prompts.promptFolderPath)); files.sort((a, b) => a.name.localeCompare(b.name)); files.forEach((file) => { if (file instanceof import_obsidian22.TFile) { const fileName = file.basename; dropdown.addOption(file.name, fileName); } }); } dropdown.setValue(""); dropdown.setValue(plugin.settings.prompts.prompt || DEFAULT_SETTINGS.prompts.prompt).onChange(async (value) => { plugin.settings.prompts.prompt = value ? value : DEFAULT_SETTINGS.prompts.prompt; await plugin.saveSettings(); }); }); new import_obsidian22.Setting(settingsContainer).setName("Prompt Folder Path").setDesc("Select a prompt from a specified folder.").addText( (text) => text.setPlaceholder("BMO/Prompts").setValue(plugin.settings.prompts.promptFolderPath || DEFAULT_SETTINGS.prompts.promptFolderPath).onChange(async (value) => { plugin.settings.prompts.promptFolderPath = value ? value : DEFAULT_SETTINGS.prompts.promptFolderPath; if (value) { let folderPath = plugin.settings.prompts.promptFolderPath.trim() || DEFAULT_SETTINGS.prompts.promptFolderPath; while (folderPath.endsWith("/")) { folderPath = folderPath.substring(0, folderPath.length - 1); plugin.settings.prompts.promptFolderPath = folderPath; } const folder = plugin.app.vault.getAbstractFileByPath(folderPath); if (folder && folder instanceof import_obsidian22.TFolder) { text.inputEl.style.borderColor = ""; } else { text.inputEl.style.borderColor = "red"; } } await plugin.saveSettings(); }).inputEl.addEventListener("focusout", async () => { SettingTab15.display(); }) ); } // src/settings.ts var BMOSettingTab = class extends import_obsidian23.PluginSettingTab { constructor(app, plugin) { super(app, plugin); this.plugin = plugin; } async display() { const { containerEl } = this; containerEl.empty(); containerEl.createEl("h1", { text: "BMO Chatbot Settings" }); const linkContainer = containerEl.createEl("div"); const links = [ { text: "Changelog", href: "https://github.com/longy2k/obsidian-bmo-chatbot/releases" }, { text: "Wiki", href: "https://github.com/longy2k/obsidian-bmo-chatbot/wiki" }, { text: "Report a Bug", href: "https://github.com/longy2k/obsidian-bmo-chatbot/issues" }, { text: "Support Me", href: "https://ko-fi.com/longy2k" } ]; links.forEach((link, index2) => { if (index2 > 0) { linkContainer.createEl("span", { text: " | ", attr: { style: "font-size: 0.8rem; margin-right: 5px;" } }); } const linkEl = linkContainer.createEl("a", { text: link.text, href: link.href, attr: { style: "font-size: 0.8rem;" } }); if (index2 < links.length - 1) { linkEl.style.marginRight = "5px"; } }); containerEl.createEl("p", { text: "Type `/help` in chat for commands." }); addHorizontalRule(this.containerEl); addProfileSettings(this.containerEl, this.plugin, this); addGeneralSettings(this.containerEl, this.plugin, this); addPromptSettings(this.containerEl, this.plugin, this); addAppearanceSettings(this.containerEl, this.plugin, this); addChatHistorySettings(this.containerEl, this.plugin, this); addEditorSettings(this.containerEl, this.plugin, this); addHorizontalRule(this.containerEl); addOllamaSettings(this.containerEl, this.plugin, this); addRESTAPIURLSettings(this.containerEl, this.plugin, this); addAPIConnectionSettings(this.containerEl, this.plugin, this); addHorizontalRule(this.containerEl); const resetButton = containerEl.createEl("a", { text: "Reset Settings", href: "#", attr: { style: "display: block; text-align: center; margin: 1rem 0; font-size: 0.7rem; color: #ff6666;" } }); resetButton.addEventListener("click", async (event) => { event.preventDefault(); const confirmReset = confirm("Are you sure you want to reset all settings to default?"); if (confirmReset) { const profilePathFile = this.plugin.settings.profiles.profileFolderPath + "/" + this.plugin.settings.profiles.profile; const profilePath = this.plugin.app.vault.getAbstractFileByPath(profilePathFile); const defaultProfilePathFile = DEFAULT_SETTINGS.profiles.profileFolderPath + "/" + DEFAULT_SETTINGS.profiles.profile; const defaultProfilePath = this.plugin.app.vault.getAbstractFileByPath(defaultProfilePathFile); if (profilePath) { if (profilePath.path === defaultProfilePath.path) { this.plugin.settings = DEFAULT_SETTINGS; await this.plugin.saveSettings(); await this.plugin.app.plugins.disablePlugin(this.plugin.manifest.id); await this.plugin.app.plugins.enablePlugin(this.plugin.manifest.id); } else { const filenameMessageHistory = "./.obsidian/plugins/bmo-chatbot/data/messageHistory_" + defaultProfilePath.name.replace(".md", ".json"); this.app.vault.adapter.remove(filenameMessageHistory); this.plugin.app.vault.delete(profilePath); this.plugin.settings.profiles.profile = DEFAULT_SETTINGS.profiles.profile; await updateSettingsFromFrontMatter(this.plugin, defaultProfilePath); await this.plugin.saveSettings(); } } requestAnimationFrame(() => { const refreshTab = this.plugin.app.setting.openTabById("bmo-chatbot"); if (refreshTab) { refreshTab.display(); } else { new BMOSettingTab(this.app, this.plugin).display(); } }); } }); } }; function addHorizontalRule(containerEl) { const separator = document.createElement("hr"); separator.style.margin = "1rem 0"; containerEl.appendChild(separator); } // src/components/editor/EditorCommands.ts var import_obsidian25 = require("obsidian"); // src/components/FetchModelEditor.ts var import_obsidian24 = require("obsidian"); async function fetchOllamaResponseEditor(settings, prompt, model, temperature, maxTokens, signal) { const ollamaRESTAPIURL = settings.OllamaConnection.RESTAPIURL; if (!ollamaRESTAPIURL) { return; } const imageMatch = prompt.match(/!?\[\[(.*?)\]\]/g); const imageLink = imageMatch ? imageMatch.map((item) => item.startsWith("!") ? item.slice(3, -2) : item.slice(2, -2)).filter((link) => /\.(jpg|jpeg|png|gif|webp|bmp|tiff|tif|svg)$/i.test(link)) : []; const imagesVaultPath = []; if (imageLink.length > 0) { imageLink.forEach((link) => { const imageFile = this.app.metadataCache.getFirstLinkpathDest(link, ""); const image = imageFile ? this.app.vault.adapter.getFullPath(imageFile.path) : null; if (image) { imagesVaultPath.push(image); } }); } try { const response = await fetch(ollamaRESTAPIURL + "/api/generate", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ model: model || settings.general.model, system: settings.editor.systen_role, prompt, images: imagesVaultPath, stream: false, keep_alive: parseInt(settings.OllamaConnection.ollamaParameters.keep_alive), options: { temperature: temperature ? parseFloat(temperature) : parseFloat(settings.general.temperature), num_predict: maxTokens ? parseInt(maxTokens) : parseInt(settings.general.max_tokens) } }), signal }); const data = await response.json(); const message = data.response.trim(); return message; } catch (error) { if (error.name === "AbortError") { console.log("Request aborted"); } else { console.error("Ollama request:", error); throw error; } } } async function fetchRESTAPIURLDataEditor(settings, prompt, model, temperature, maxTokens, signal) { try { const response = await fetch(settings.RESTAPIURLConnection.RESTAPIURL + "/chat/completions", { method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${settings.RESTAPIURLConnection.APIKey}` }, body: JSON.stringify({ model: model || settings.general.model, messages: [ { role: "system", content: settings.editor.systen_role || "You are a helpful assistant." }, { role: "user", content: prompt } ], max_tokens: parseInt(maxTokens || settings.general.max_tokens || "-1"), temperature: parseFloat(temperature || settings.general.temperature) }), signal }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); const message = data.choices[0].message.content.trim(); return message; } catch (error) { console.error("Error making API request:", error); throw error; } } async function fetchAnthropicResponseEditor(settings, prompt, model, temperature, maxTokens, signal) { try { const response = await (0, import_obsidian24.requestUrl)({ url: "https://api.anthropic.com/v1/messages", method: "POST", headers: { "anthropic-version": "2023-06-01", "content-type": "application/json", "x-api-key": settings.APIConnections.anthropic.APIKey }, body: JSON.stringify({ model: model || settings.general.model, system: settings.editor.systen_role, messages: [ { role: "user", content: prompt } ], max_tokens: parseInt(maxTokens || settings.general.max_tokens) || 4096, temperature: parseFloat(temperature || settings.general.temperature) }) }); const message = response.json.content[0].text.trim(); return message; } catch (error) { console.error(error); } } async function fetchGoogleGeminiDataEditor(settings, prompt, model, temperature, maxTokens, signal) { try { const response = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent?key=${settings.APIConnections.googleGemini.APIKey}`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ contents: [ { parts: [ { text: settings.editor.systen_role + prompt } ] } ], model: model || settings.general.model, generationConfig: { temperature: parseFloat(temperature || settings.general.temperature), maxOutputTokens: parseInt(maxTokens || settings.general.max_tokens) || 4096 } }), signal }); const data = await response.json(); const message = data.candidates[0].content.parts[0].text.trim(); return message; } catch (error) { console.error(error); } } async function fetchMistralDataEditor(settings, prompt, model, temperature, maxTokens, signal) { try { const response = await fetch("https://api.mistral.ai/v1/chat/completions", { method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${settings.APIConnections.mistral.APIKey}` }, body: JSON.stringify({ model: model || settings.general.model, messages: [ { role: "system", content: settings.editor.systen_role }, { role: "user", content: prompt } ], max_tokens: parseInt(maxTokens || settings.general.max_tokens), temperature: parseFloat(temperature || settings.general.temperature) }), signal }); const data = await response.json(); const message = data.choices[0].message.content.trim(); return message; } catch (error) { console.error(error); } } async function fetchOpenAIBaseAPIResponseEditor(settings, prompt, model, temperature, maxTokens, signal) { const response = await fetch(`${settings.APIConnections.openAI.openAIBaseUrl}/chat/completions`, { method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${settings.APIConnections.openAI.APIKey}` }, body: JSON.stringify({ model: model || settings.general.model, max_tokens: parseInt(maxTokens || settings.general.max_tokens), temperature: parseFloat(temperature || settings.general.temperature), stream: false, messages: [ { role: "system", content: settings.editor.systen_role }, { role: "user", content: prompt } ] }), signal }); const data = await response.json(); const message = data.choices[0].message.content || ""; return message; } async function fetchOpenRouterEditor(settings, prompt, model, temperature, maxTokens, signal) { try { const response = await fetch("https://openrouter.ai/api/v1/chat/completions", { method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${settings.APIConnections.openRouter.APIKey}` }, body: JSON.stringify({ model: model || settings.general.model, messages: [ { role: "system", content: settings.editor.systen_role }, { role: "user", content: prompt } ], max_tokens: parseInt(maxTokens || settings.general.max_tokens), temperature: parseFloat(temperature || settings.general.temperature) }), signal }); const data = await response.json(); const message = data.choices[0].message.content.trim(); return message; } catch (error) { console.error("Error making API request:", error); throw error; } } // src/components/editor/EditorCommands.ts async function renameTitleCommand(plugin, settings) { var _a2, _b, _c; let uniqueNameFound = false; let modelRenameTitle; let folderName = ((_c = (_b = plugin.app.vault.getAbstractFileByPath(((_a2 = plugin.app.workspace.getActiveFile()) == null ? void 0 : _a2.path) || "")) == null ? void 0 : _b.parent) == null ? void 0 : _c.path) || ""; const fileExtension = ".md"; const allFiles = plugin.app.vault.getFiles(); const activeFile = plugin.app.workspace.getActiveFile(); let fileContent = ""; try { new import_obsidian25.Notice("Generating title..."); if (activeFile) { fileContent = await plugin.app.vault.read(activeFile); } if (folderName && !folderName.endsWith("/")) { folderName += "/"; } const fileNameExists = (name) => { return allFiles.some((file) => file.path === folderName + name + fileExtension); }; while (!uniqueNameFound) { modelRenameTitle = await fetchModelRenameTitle(settings, fileContent); if (!fileNameExists(modelRenameTitle)) { uniqueNameFound = true; } } const fileName = folderName + modelRenameTitle + fileExtension; if (activeFile) { plugin.app.vault.rename(activeFile, fileName); } new import_obsidian25.Notice("Renamed note title."); } catch (error) { console.error(error); } } async function promptSelectGenerateCommand(plugin, settings) { var _a2, _b; const view = plugin.app.workspace.getActiveViewOfType(import_obsidian25.MarkdownView); const select = view == null ? void 0 : view.editor.getSelection(); if (view && select && select.trim() !== "") { const generatingNotice = new import_obsidian25.Notice("Generating...", 0); if (settings.OllamaConnection.RESTAPIURL && settings.OllamaConnection.ollamaModels.includes(settings.general.model)) { try { const response = await fetchOllamaResponseEditor(settings, select); const cursorStart = view.editor.getCursor("from"); view.editor.replaceSelection(response != null ? response : "ERROR"); const cursorEnd = { line: cursorStart.line, ch: cursorStart.ch + (response != null ? response : "ERROR").length }; view.editor.setSelection(cursorStart, cursorEnd); } catch (error) { new import_obsidian25.Notice("Error occurred while fetching completion: " + error.message); console.log(error.message); } } else if (settings.RESTAPIURLConnection.RESTAPIURL && settings.RESTAPIURLConnection.RESTAPIURLModels.includes(settings.general.model)) { try { const response = await fetchRESTAPIURLDataEditor(settings, select); const cursorStart = view.editor.getCursor("from"); view.editor.replaceSelection(response); const cursorEnd = { line: cursorStart.line, ch: cursorStart.ch + (response == null ? void 0 : response.length) }; view.editor.setSelection(cursorStart, cursorEnd); } catch (error) { new import_obsidian25.Notice("Error occurred while fetching completion: " + error.message); console.log(error.message); } } else if (ANTHROPIC_MODELS.includes(settings.general.model)) { try { const response = await fetchAnthropicResponseEditor(settings, select); view.editor.replaceSelection(response); } catch (error) { new import_obsidian25.Notice("Error occurred while fetching completion: " + error.message); console.log(error.message); } } else if (settings.APIConnections.googleGemini.geminiModels.includes(settings.general.model)) { try { const response = await fetchGoogleGeminiDataEditor(settings, select); const cursorStart = view.editor.getCursor("from"); view.editor.replaceSelection(response); const cursorEnd = { line: cursorStart.line, ch: cursorStart.ch + (response == null ? void 0 : response.length) }; view.editor.setSelection(cursorStart, cursorEnd); } catch (error) { new import_obsidian25.Notice("Error occurred while fetching completion: " + error.message); console.log(error.message); } } else if (settings.APIConnections.mistral.mistralModels.includes(settings.general.model)) { try { const response = await fetchMistralDataEditor(settings, select); const cursorStart = view.editor.getCursor("from"); view.editor.replaceSelection(response); const cursorEnd = { line: cursorStart.line, ch: cursorStart.ch + (response == null ? void 0 : response.length) }; view.editor.setSelection(cursorStart, cursorEnd); } catch (error) { new import_obsidian25.Notice("Error occurred while fetching completion: " + error.message); console.log(error.message); } } else if (OPENAI_MODELS.includes(settings.general.model)) { try { const response = await fetchOpenAIBaseAPIResponseEditor(settings, select); const cursorStart = view.editor.getCursor("from"); view.editor.replaceSelection(response || ""); const cursorEnd = { line: cursorStart.line, ch: cursorStart.ch + ((_a2 = response == null ? void 0 : response.length) != null ? _a2 : 0) }; view.editor.setSelection(cursorStart, cursorEnd); } catch (error) { new import_obsidian25.Notice("Error occurred while fetching completion: " + error.message); console.log(error.message); } } else if (settings.APIConnections.openAI.openAIBaseUrl != DEFAULT_SETTINGS.APIConnections.openAI.openAIBaseUrl && settings.APIConnections.openAI.openAIBaseModels.includes(settings.general.model)) { try { const response = await fetchOpenAIBaseAPIResponseEditor(settings, select); const cursorStart = view.editor.getCursor("from"); view.editor.replaceSelection(response || ""); const cursorEnd = { line: cursorStart.line, ch: cursorStart.ch + ((_b = response == null ? void 0 : response.length) != null ? _b : 0) }; view.editor.setSelection(cursorStart, cursorEnd); } catch (error) { new import_obsidian25.Notice("Error occurred while fetching completion: " + error.message); console.log(error.message); } } else if (settings.APIConnections.openRouter.openRouterModels.includes(settings.general.model)) { try { const response = await fetchOpenRouterEditor(settings, select); const cursorStart = view.editor.getCursor("from"); view.editor.replaceSelection(response); const cursorEnd = { line: cursorStart.line, ch: cursorStart.ch + (response == null ? void 0 : response.length) }; view.editor.setSelection(cursorStart, cursorEnd); } catch (error) { new import_obsidian25.Notice("Error occurred while fetching completion: " + error.message); console.log(error.message); } } generatingNotice.hide(); new import_obsidian25.Notice("Generation complete."); } else { new import_obsidian25.Notice("No text selected."); } } // src/components/editor/BMOCodeBlockProcessor.ts var import_obsidian26 = require("obsidian"); function bmoCodeBlockProcessor(plugin, settings) { let previousPrompt = ""; let abortController2 = null; return plugin.registerMarkdownCodeBlockProcessor("bmo", async (source, el, ctx) => { if (abortController2) { abortController2.abort(); } abortController2 = new AbortController(); const file = plugin.app.workspace.getActiveFile(); if (file && settings.general.model !== "") { const fileContent = await plugin.app.vault.read(file); const codeBlockRegex = /```bmo\n([\s\S]*?)```/g; let match; let updatedFileContent = fileContent; while ((match = codeBlockRegex.exec(fileContent)) !== null) { const originalCodeBlock = match[0]; const codeBlockContent = match[1]; if (!codeBlockContent.includes("MODEL ")) { const updatedSource = "MODEL " + settings.general.model + "\n" + codeBlockContent; updatedFileContent = updatedFileContent.replace(originalCodeBlock, "```bmo\n" + updatedSource + "```"); } } if (updatedFileContent !== fileContent) { await plugin.app.vault.modify(file, updatedFileContent); } } let modelName = "No Model"; let temperature = "1.0"; let maxTokens = ""; let contentToRender = ""; const modelMatch = source.match(/MODEL\s+(.+)/); if (modelMatch) { modelName = modelMatch[1].trim(); } const temperatureMatch = source.match(/TEMPERATURE\s+(.+)/); if (temperatureMatch) { temperature = temperatureMatch[1].trim(); } const maxTokensMatch = source.match(/MAX_TOKENS\s+(.+)/); if (maxTokensMatch) { maxTokens = maxTokensMatch[1].trim(); } const promptMatch = source.match(/^(?:MODEL.*\n|TEMPERATURE.*\n|MAX_TOKENS.*\n)*([\s\S]*?)(?=\s*|$)/); let prompt = ""; if (promptMatch) { prompt = promptMatch[1].trim(); } if (prompt !== previousPrompt) { previousPrompt = prompt; } const responseMatch = source.match(/([\s\S]*?)<\/response>/); if (responseMatch) { contentToRender = responseMatch[1].trim(); } const container = el.createEl("div"); container.style.position = "relative"; const bmoCodeBlockContainer = container.createEl("div", { cls: "bmoCodeBlockContainer" }); bmoCodeBlockContainer.dataset.callout = "chat"; bmoCodeBlockContainer.style.backgroundColor = settings.appearance.bmoGenerateBackgroundColor; bmoCodeBlockContainer.style.border = "1px solid #0a0f0a"; bmoCodeBlockContainer.style.borderRadius = "5px"; bmoCodeBlockContainer.style.padding = "10px"; bmoCodeBlockContainer.style.marginBottom = "10px"; const bmoCodeBlockContent = bmoCodeBlockContainer.createEl("div", { cls: "bmoCodeBlockContent" }); bmoCodeBlockContent.style.color = settings.appearance.bmoGenerateFontColor; bmoCodeBlockContent.style.whiteSpace = "normal"; const bottomContainer = container.createEl("div"); bottomContainer.style.display = "flex"; bottomContainer.style.justifyContent = "space-between"; bottomContainer.style.alignItems = "center"; bottomContainer.style.marginTop = "10px"; const modelText = bottomContainer.createEl("span"); modelText.textContent = modelName; modelText.style.fontSize = "0.9em"; modelText.style.color = "#666"; modelText.style.fontWeight = "bold"; const loaderCircle = bottomContainer.createEl("div"); loaderCircle.classList.add("loader-circle"); loaderCircle.style.width = "20px"; loaderCircle.style.height = "20px"; loaderCircle.style.border = "2px solid #666"; loaderCircle.style.borderTopColor = "transparent"; loaderCircle.style.borderRadius = "50%"; loaderCircle.style.animation = "spin 1s linear infinite"; loaderCircle.style.display = "none"; const bmoGenerationNotice = bottomContainer.createEl("span"); bmoGenerationNotice.textContent = "Done!"; bmoGenerationNotice.style.fontSize = "0.9em"; bmoGenerationNotice.style.color = "#4caf50"; bmoGenerationNotice.style.display = "none"; const button = bottomContainer.createEl("button"); button.textContent = "Generate"; button.onclick = async () => { if (button.textContent === "Cancel") { if (abortController2) { abortController2.abort(); abortController2 = null; } button.textContent = "Generate"; loaderCircle.style.display = "none"; bmoGenerationNotice.textContent = "Aborted."; bmoGenerationNotice.style.color = "#ff6666"; bmoGenerationNotice.style.display = "inline"; setTimeout(() => { bmoGenerationNotice.style.display = "none"; }, 2e3); return; } button.textContent = "Cancel"; if (!abortController2) { abortController2 = new AbortController(); } const signal = abortController2.signal; loaderCircle.style.display = "block"; let modelResponse = ""; try { if (settings.OllamaConnection.ollamaModels.includes(modelName)) { modelResponse = await fetchOllamaResponseEditor(settings, prompt, modelName, temperature, maxTokens, signal) || contentToRender; } else if (settings.RESTAPIURLConnection.RESTAPIURLModels.includes(modelName)) { modelResponse = await fetchRESTAPIURLDataEditor(settings, prompt, modelName, temperature, maxTokens, signal) || contentToRender; } else if (settings.APIConnections.anthropic.anthropicModels.includes(modelName)) { button.disabled = true; modelResponse = await fetchAnthropicResponseEditor(settings, prompt, modelName, temperature, maxTokens, signal) || contentToRender; } else if (settings.APIConnections.googleGemini.geminiModels.includes(modelName)) { modelResponse = await fetchGoogleGeminiDataEditor(settings, prompt, modelName, temperature, maxTokens, signal) || contentToRender; } else if (settings.APIConnections.mistral.mistralModels.includes(modelName)) { modelResponse = await fetchMistralDataEditor(settings, prompt, modelName, temperature, maxTokens, signal) || contentToRender; } else if (settings.APIConnections.openAI.openAIBaseModels.includes(modelName)) { modelResponse = await fetchOpenAIBaseAPIResponseEditor(settings, prompt, modelName, temperature, maxTokens, signal) || contentToRender; } else if (settings.APIConnections.openRouter.openRouterModels.includes(modelName)) { modelResponse = await fetchOpenRouterEditor(settings, prompt, modelName, temperature, maxTokens, signal) || contentToRender; } else { bmoGenerationNotice.textContent = "Model not found."; bmoGenerationNotice.style.color = "#ff6666"; bmoGenerationNotice.style.display = "inline"; setTimeout(() => { bmoGenerationNotice.style.display = "none"; button.textContent = "Generate"; }, 2e3); } if (modelResponse !== "") { if (!modelResponse.includes("\\`")) { modelResponse = modelResponse.replace(/`/g, "\\`"); } const responseTagsExist = source.includes("") && source.includes(""); let updatedSource = source; if (responseTagsExist) { updatedSource = source.replace( /[\s\S]*?<\/response>/, ` ${modelResponse} ` ); } else { updatedSource = `${source} ${modelResponse} `; } const newResponseMatch = updatedSource.match(/([\s\S]*?)<\/response>/); if (newResponseMatch) { contentToRender = newResponseMatch[1].trim(); } const file2 = plugin.app.workspace.getActiveFile(); if (file2) { const fileContent = await plugin.app.vault.read(file2); const updatedFileContent = fileContent.replace(source, updatedSource); await plugin.app.vault.modify(file2, updatedFileContent); } } loaderCircle.style.display = "none"; } catch (error) { if (error.name === "AbortError") { console.log("BMO Generate Aborted."); button.textContent = "Generate"; loaderCircle.style.display = "none"; bmoGenerationNotice.textContent = "Aborted."; bmoGenerationNotice.style.color = "#ff6666"; bmoGenerationNotice.style.display = "inline"; setTimeout(() => { bmoGenerationNotice.style.display = "none"; }, 2e3); return; } else { console.error("Generation error:", error); bmoGenerationNotice.textContent = "Error occurred."; bmoGenerationNotice.style.color = "#ff6666"; bmoGenerationNotice.style.display = "inline"; setTimeout(() => { bmoGenerationNotice.style.display = "none"; }, 2e3); } } }; if (source.includes("") && source.includes("")) { await import_obsidian26.MarkdownRenderer.render(plugin.app, contentToRender, bmoCodeBlockContent, "/", plugin); } else { await import_obsidian26.MarkdownRenderer.render(plugin.app, prompt, bmoCodeBlockContent, "/", plugin); } }); } // src/main.ts var DEFAULT_SETTINGS = { profiles: { profile: "BMO.md", profileFolderPath: "BMO/Profiles", lastLoadedChatHistoryPath: null, lastLoadedChatHistory: [] }, general: { model: "", system_role: "You are a helpful assistant.", max_tokens: "", temperature: "1.00", enableReferenceCurrentNote: false }, appearance: { userName: "YOU", chatbotName: "BMO", chatbotContainerBackgroundColor: "--background-secondary", messageContainerBackgroundColor: "--background-secondary", userMessageFontColor: "--text-normal", userMessageBackgroundColor: "--background-primary", botMessageFontColor: "--text-normal", botMessageBackgroundColor: "--background-secondary", chatBoxFontColor: "--text-normal", chatBoxBackgroundColor: "--interactive-accent", enableHeader: true, enableScrollBar: false, bmoGenerateBackgroundColor: "#0c0a12", bmoGenerateFontColor: "--text-normal" }, prompts: { prompt: "", promptFolderPath: "BMO/Prompts" }, editor: { systen_role: "You are a helpful assistant." }, chatHistory: { chatHistoryPath: "BMO/History", templateFilePath: "", allowRenameNoteTitle: false }, OllamaConnection: { RESTAPIURL: "http://localhost:11434", enableStream: true, ollamaParameters: { mirostat: "0", mirostat_eta: "0.10", mirostat_tau: "5.00", num_ctx: "2048", num_gqa: "", num_thread: "", repeat_last_n: "64", repeat_penalty: "1.10", seed: "", stop: [], tfs_z: "1.00", top_k: "40", top_p: "0.90", min_p: "0.0", keep_alive: "" }, ollamaModels: [] }, RESTAPIURLConnection: { APIKey: "", RESTAPIURL: "", enableStream: false, RESTAPIURLModels: [] }, APIConnections: { anthropic: { APIKey: "", anthropicModels: [] }, googleGemini: { APIKey: "", enableStream: false, geminiModels: [] }, mistral: { APIKey: "", enableStream: false, mistralModels: [] }, openAI: { APIKey: "", openAIBaseUrl: "https://api.openai.com/v1", enableStream: true, openAIBaseModels: [] }, openRouter: { APIKey: "", enableStream: false, openRouterModels: [] } }, toggleGeneralSettings: true, toggleAppearanceSettings: false, togglePromptSettings: false, toggleEditorSettings: false, toggleChatHistorySettings: false, toggleProfileSettings: false, toggleAPIConnectionSettings: true, toggleOpenAISettings: false, toggleMistralSettings: false, toggleGoogleGeminiSettings: false, toggleAnthropicSettings: false, toggleRESTAPIURLSettings: true, toggleOpenRouterSettings: false, toggleOllamaSettings: true, toggleAdvancedSettings: false }; var checkActiveFile = null; var BMOGPT15 = class extends import_obsidian27.Plugin { async onload() { await this.loadSettings(); const folderPath = this.settings.profiles.profileFolderPath || DEFAULT_SETTINGS.profiles.profileFolderPath; const defaultFilePath = `${folderPath}/${DEFAULT_SETTINGS.profiles.profile}`; const defaultProfile = this.app.vault.getAbstractFileByPath(defaultFilePath); if (!await this.app.vault.adapter.exists(folderPath)) { await this.app.vault.createFolder(folderPath); } if (!await this.app.vault.adapter.exists(defaultFilePath)) { this.app.vault.create(defaultFilePath, ""); console.log("Default profile created."); } this.registerEvent( this.app.vault.on("create", async (file) => { if (file instanceof import_obsidian27.TFile && file.path.startsWith(folderPath)) { const fileContent = await this.app.vault.read(file); if (fileContent.trim() === "") { defaultFrontMatter(this, file); } const profileFiles = this.app.vault.getFiles().filter((file2) => file2.path.startsWith(this.settings.profiles.profileFolderPath)); profileFiles.sort((a, b) => a.name.localeCompare(b.name)); if (this.settings.profiles.lastLoadedChatHistory.length === 0) { profileFiles.forEach((profile, index2) => { if (!this.settings.profiles.lastLoadedChatHistory[index2]) { this.settings.profiles.lastLoadedChatHistory[index2] = null; } }); } else { if (this.settings.profiles.lastLoadedChatHistory.length !== profileFiles.length) { const profileIndex = profileFiles.findIndex((profileFiles2) => profileFiles2.basename === file.basename); this.settings.profiles.lastLoadedChatHistory.splice(profileIndex, 0, null); } } await this.saveSettings(); } }) ); this.registerEvent( this.app.vault.on( "delete", async (file) => { const profileFiles = this.app.vault.getFiles().filter((file2) => file2.path.startsWith(this.settings.profiles.profileFolderPath)); profileFiles.sort((a, b) => a.name.localeCompare(b.name)); if (file instanceof import_obsidian27.TFile && file.path.startsWith(this.settings.chatHistory.chatHistoryPath)) { const currentProfile = this.settings.profiles.profile.replace(/\.[^/.]+$/, ""); const profileIndex = profileFiles.findIndex((file2) => file2.basename === currentProfile); const currentIndex = this.settings.profiles.lastLoadedChatHistory.indexOf(file.path); if (this.settings.profiles.lastLoadedChatHistory[currentIndex] === file.path) { this.settings.profiles.lastLoadedChatHistory[currentIndex] = null; } if (profileIndex === currentIndex) { this.settings.profiles.lastLoadedChatHistoryPath = null; } } if (file instanceof import_obsidian27.TFile && file.path.startsWith(folderPath)) { const filenameMessageHistory = "./.obsidian/plugins/bmo-chatbot/data/messageHistory_" + file.name.replace(".md", ".json"); this.app.vault.adapter.remove(filenameMessageHistory); const profileIndex = profileFiles.findIndex((profileFile) => profileFile.name > file.name); this.settings.profiles.lastLoadedChatHistory.splice(profileIndex, 1); if (file.path === defaultFilePath) { this.settings = DEFAULT_SETTINGS; this.app.vault.create(defaultFilePath, ""); await updateSettingsFromFrontMatter(this, defaultProfile); } else { if (this.settings.profiles.profile === file.name) { this.settings.profiles.profile = DEFAULT_SETTINGS.profiles.profile; const profileFiles2 = this.app.vault.getFiles().filter((file2) => file2.path.startsWith(this.settings.profiles.profileFolderPath)); profileFiles2.sort((a, b) => a.name.localeCompare(b.name)); const currentProfile = this.settings.profiles.profile.replace(/\.[^/.]+$/, ""); const profileIndex2 = profileFiles2.findIndex((file2) => file2.basename === currentProfile); if (this.settings.profiles.lastLoadedChatHistoryPath !== null) { this.settings.profiles.lastLoadedChatHistoryPath = this.settings.profiles.lastLoadedChatHistory[profileIndex2]; } const fileContent = (await this.app.vault.read(defaultProfile)).replace(/^---\s*[\s\S]*?---/, "").trim(); this.settings.general.system_role = fileContent; await updateSettingsFromFrontMatter(this, defaultProfile); } } } await this.saveSettings(); } ) ); this.registerEvent( this.app.vault.on( "modify", async (file) => { const currentProfilePath = `${folderPath}/${this.settings.profiles.profile}`; if (file.path === currentProfilePath) { await updateSettingsFromFrontMatter(this, file); const fileContent = (await this.app.vault.read(file)).replace(/^---\s*[\s\S]*?---/, "").trim(); this.settings.general.system_role = fileContent; await this.saveSettings(); } } ) ); this.registerEvent( this.app.vault.on("rename", async (file, oldPath) => { try { const currentProfilePath = `${folderPath}/${this.settings.profiles.profile}`; if (oldPath === currentProfilePath) { this.settings.profiles.profile = file.name; this.settings.appearance.chatbotName = file.basename; await this.saveSettings(); } if (file instanceof import_obsidian27.TFile && file.path.startsWith(folderPath)) { const filenameMessageHistoryPath = "./.obsidian/plugins/bmo-chatbot/data/"; const oldProfileMessageHistory = "messageHistory_" + oldPath.replace(folderPath + "/", "").replace(".md", ".json"); await this.app.vault.adapter.rename(filenameMessageHistoryPath + oldProfileMessageHistory, filenameMessageHistoryPath + "messageHistory_" + file.name.replace(".md", ".json")).catch((error) => { console.error("Error handling rename event:", error); }); await this.app.vault.adapter.remove(filenameMessageHistoryPath + oldProfileMessageHistory); } } catch (error) { if (error.message.includes("ENOENT: no such file or directory, unlink")) { } else { console.error("Error handling rename event:", error); } } const profileFiles = this.app.vault.getFiles().filter((file2) => file2.path.startsWith(this.settings.profiles.profileFolderPath)); profileFiles.sort((a, b) => a.name.localeCompare(b.name)); const currentIndex = profileFiles.findIndex((profileFile) => profileFile.path === file.path); const prevFileName = oldPath.replace(folderPath + "/", ""); const updatedProfileFiles = [...profileFiles, { name: prevFileName }]; updatedProfileFiles.sort((a, b) => a.name.localeCompare(b.name)); const fileIndex = updatedProfileFiles.findIndex((profileFile) => profileFile.name === file.name); if (fileIndex !== -1) { updatedProfileFiles.splice(fileIndex, 1); } const prevIndex = updatedProfileFiles.findIndex((profileFile) => profileFile.name === prevFileName); if (currentIndex !== -1) { const [removed] = this.settings.profiles.lastLoadedChatHistory.splice(prevIndex, 1); this.settings.profiles.lastLoadedChatHistory.splice(currentIndex, 0, removed); } const currentProfile = this.settings.profiles.profile.replace(/\.[^/.]+$/, ""); const profileIndex = profileFiles.findIndex((file2) => file2.basename === currentProfile); const index2 = this.settings.profiles.lastLoadedChatHistory.indexOf(oldPath); if (this.settings.profiles.lastLoadedChatHistory[profileIndex] === oldPath) { this.settings.profiles.lastLoadedChatHistory[index2] = file.path; this.settings.profiles.lastLoadedChatHistoryPath = file.path; } else if (this.settings.profiles.lastLoadedChatHistory[index2] === oldPath) { this.settings.profiles.lastLoadedChatHistory[index2] = file.path; } await this.saveSettings(); }) ); this.registerEvent( this.app.workspace.on("active-leaf-change", () => { this.handleFileSwitch(); }) ); this.registerView( VIEW_TYPE_CHATBOT, (leaf) => new BMOView(leaf, this.settings, this) ); this.addRibbonIcon("bot", "BMO Chatbot", () => { this.activateView(); }); this.addCommand({ id: "open-bmo-chatbot", name: "Open BMO Chatbot", callback: () => { this.activateView(); }, hotkeys: [ { modifiers: ["Mod"], key: "0" } ] }); this.addCommand({ id: "rename-note-title", name: "Rename Note Title", callback: () => { renameTitleCommand(this, this.settings); }, hotkeys: [ { modifiers: ["Mod"], key: "'" } ] }); this.registerEvent( this.app.workspace.on("file-menu", (menu, file) => { if (!(file instanceof import_obsidian27.TFile)) { return; } menu.addItem((item) => { item.setTitle("BMO Chatbot: Generate new title").onClick(() => renameTitleCommand(this, this.settings)); }); }) ); this.addCommand({ id: "prompt-select-generate", name: "Prompt Select Generate", callback: () => { promptSelectGenerateCommand(this, this.settings); }, hotkeys: [ { modifiers: ["Mod", "Shift"], key: "=" } ] }); bmoCodeBlockProcessor(this, this.settings); this.addSettingTab(new BMOSettingTab(this.app, this)); } handleFileSwitch() { checkActiveFile = this.app.workspace.getActiveFile(); } async onunload() { this.app.workspace.getLeavesOfType(VIEW_TYPE_CHATBOT).forEach((leaf) => { const bmoView = leaf.view; if (bmoView) { this.saveSettings(); } }); } async activateView() { this.app.workspace.detachLeavesOfType(VIEW_TYPE_CHATBOT); const rightLeaf = this.app.workspace.getRightLeaf(false); await (rightLeaf == null ? void 0 : rightLeaf.setViewState({ type: VIEW_TYPE_CHATBOT, active: true })); this.app.workspace.revealLeaf( this.app.workspace.getLeavesOfType(VIEW_TYPE_CHATBOT)[0] ); const textarea = document.querySelector(".chatbox textarea"); if (textarea) { textarea.style.opacity = "0"; textarea.style.transition = "opacity 1s ease-in-out"; setTimeout(() => { textarea.focus(); textarea.style.opacity = "1"; }, 50); } this.app.workspace.revealLeaf( this.app.workspace.getLeavesOfType(VIEW_TYPE_CHATBOT)[0] ); const messageContainer = document.querySelector("#messageContainer"); if (messageContainer) { messageContainer.scroll({ top: messageContainer.scrollHeight, behavior: "smooth" }); } } async loadSettings() { this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()); } async saveSettings() { const currentProfileFile = `${this.settings.profiles.profileFolderPath}/${this.settings.profiles.profile}`; const currentProfile = this.app.vault.getAbstractFileByPath(currentProfileFile); updateFrontMatter(this, currentProfile); const header = document.querySelector("#header"); const modelOptions = header == null ? void 0 : header.querySelector("#modelOptions"); if (modelOptions) { modelOptions.remove(); } const populateModelOptions = populateModelDropdown(this, this.settings); header == null ? void 0 : header.appendChild(populateModelOptions); await this.saveData(this.settings); } }; async function defaultFrontMatter(plugin, file) { const setDefaultFrontMatter = async (frontmatter) => { frontmatter.model = DEFAULT_SETTINGS.general.model; frontmatter.max_tokens = parseInt(DEFAULT_SETTINGS.general.max_tokens); frontmatter.temperature = parseFloat(DEFAULT_SETTINGS.general.temperature); frontmatter.enable_reference_current_note = DEFAULT_SETTINGS.general.enableReferenceCurrentNote; frontmatter.prompt = DEFAULT_SETTINGS.prompts.prompt; frontmatter.user_name = DEFAULT_SETTINGS.appearance.userName; frontmatter.enable_header = DEFAULT_SETTINGS.appearance.enableHeader; frontmatter.chatbot_container_background_color = DEFAULT_SETTINGS.appearance.chatbotContainerBackgroundColor.replace(/^#/, ""); frontmatter.message_container_background_color = DEFAULT_SETTINGS.appearance.messageContainerBackgroundColor.replace(/^#/, ""); frontmatter.user_message_font_color = DEFAULT_SETTINGS.appearance.userMessageFontColor.replace(/^#/, ""); frontmatter.user_message_background_color = DEFAULT_SETTINGS.appearance.userMessageBackgroundColor.replace(/^#/, ""); frontmatter.bot_message_font_color = DEFAULT_SETTINGS.appearance.botMessageFontColor.replace(/^#/, ""); frontmatter.chatbot_message_background_color = DEFAULT_SETTINGS.appearance.botMessageBackgroundColor.replace(/^#/, ""); frontmatter.chatbox_font_color = DEFAULT_SETTINGS.appearance.chatBoxFontColor.replace(/^#/, ""); frontmatter.chatbox_background_color = DEFAULT_SETTINGS.appearance.chatBoxBackgroundColor.replace(/^#/, ""); frontmatter.bmo_generate_background_color = DEFAULT_SETTINGS.appearance.bmoGenerateBackgroundColor.replace(/^#/, ""); frontmatter.bmo_generate_font_color = DEFAULT_SETTINGS.appearance.bmoGenerateFontColor.replace(/^#/, ""); frontmatter.systen_role = DEFAULT_SETTINGS.editor.systen_role; frontmatter.ollama_mirostat = parseFloat(DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.mirostat); frontmatter.ollama_mirostat_eta = parseFloat(DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.mirostat_eta); frontmatter.ollama_mirostat_tau = parseFloat(DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.mirostat_tau); frontmatter.ollama_num_ctx = parseInt(DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.num_ctx); frontmatter.ollama_num_gqa = parseInt(DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.num_gqa); frontmatter.ollama_num_thread = parseInt(DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.num_thread); frontmatter.ollama_repeat_last_n = parseInt(DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.repeat_last_n); frontmatter.ollama_repeat_penalty = parseFloat(DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.repeat_penalty); frontmatter.ollama_seed = parseInt(DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.seed); frontmatter.ollama_stop = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.stop; frontmatter.ollama_tfs_z = parseFloat(DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.tfs_z); frontmatter.ollama_top_k = parseInt(DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.top_k); frontmatter.ollama_top_p = parseFloat(DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.top_p); frontmatter.ollama_min_p = parseFloat(DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.min_p); frontmatter.ollama_keep_alive = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.keep_alive; }; const writeOptions = { // Specify options if needed }; try { await plugin.app.fileManager.processFrontMatter(file, setDefaultFrontMatter, writeOptions); } catch (error) { console.error("Error processing frontmatter:", error); } plugin.app.vault.append(file, DEFAULT_SETTINGS.general.system_role); } async function updateSettingsFromFrontMatter(plugin, file) { const updateSettings = async (frontmatter) => { plugin.settings.general.model = frontmatter.model; plugin.settings.general.max_tokens = frontmatter.max_tokens; plugin.settings.general.temperature = frontmatter.temperature; plugin.settings.general.enableReferenceCurrentNote = frontmatter.enable_reference_current_note; plugin.settings.prompts.prompt = frontmatter.prompt; plugin.settings.appearance.userName = frontmatter.user_name; plugin.settings.appearance.chatbotName = file.basename; plugin.settings.appearance.enableHeader = frontmatter.enable_header; plugin.settings.appearance.chatbotContainerBackgroundColor = "#" + frontmatter.chatbot_container_background_color; plugin.settings.appearance.messageContainerBackgroundColor = "#" + frontmatter.message_container_background_color; plugin.settings.appearance.userMessageFontColor = "#" + frontmatter.user_message_font_color; plugin.settings.appearance.userMessageBackgroundColor = "#" + frontmatter.user_message_background_color; plugin.settings.appearance.botMessageFontColor = "#" + frontmatter.bot_message_font_color; plugin.settings.appearance.botMessageBackgroundColor = "#" + frontmatter.chatbot_message_background_color; plugin.settings.appearance.chatBoxFontColor = "#" + frontmatter.chatbox_font_color; plugin.settings.appearance.chatBoxBackgroundColor = "#" + frontmatter.chatbox_background_color; plugin.settings.appearance.bmoGenerateBackgroundColor = "#" + frontmatter.bmo_generate_background_color; plugin.settings.appearance.bmoGenerateFontColor = "#" + frontmatter.bmo_generate_font_color; plugin.settings.editor.systen_role = frontmatter.systen_role; plugin.settings.OllamaConnection.ollamaParameters.mirostat = frontmatter.ollama_mirostat; plugin.settings.OllamaConnection.ollamaParameters.mirostat_eta = frontmatter.ollama_mirostat_eta; plugin.settings.OllamaConnection.ollamaParameters.mirostat_tau = frontmatter.ollama_mirostat_tau; plugin.settings.OllamaConnection.ollamaParameters.num_ctx = frontmatter.ollama_num_ctx; plugin.settings.OllamaConnection.ollamaParameters.num_gqa = frontmatter.ollama_num_gqa; plugin.settings.OllamaConnection.ollamaParameters.num_thread = frontmatter.ollama_num_thread; plugin.settings.OllamaConnection.ollamaParameters.repeat_last_n = frontmatter.ollama_repeat_last_n; plugin.settings.OllamaConnection.ollamaParameters.repeat_penalty = frontmatter.ollama_repeat_penalty; plugin.settings.OllamaConnection.ollamaParameters.seed = frontmatter.ollama_seed; plugin.settings.OllamaConnection.ollamaParameters.stop = frontmatter.ollama_stop; plugin.settings.OllamaConnection.ollamaParameters.tfs_z = frontmatter.ollama_tfs_z; plugin.settings.OllamaConnection.ollamaParameters.top_k = frontmatter.ollama_top_k; plugin.settings.OllamaConnection.ollamaParameters.top_p = frontmatter.ollama_top_p; plugin.settings.OllamaConnection.ollamaParameters.min_p = frontmatter.ollama_min_p; plugin.settings.OllamaConnection.ollamaParameters.keep_alive = frontmatter.ollama_keep_alive; }; const writeOptions = { // Specify options if needed }; try { await plugin.app.fileManager.processFrontMatter(file, updateSettings, writeOptions); const fileContent = (await plugin.app.vault.read(file)).replace(/^---\s*[\s\S]*?---/, "").trim(); plugin.settings.general.system_role = fileContent; updateProfile(plugin, file); } catch (error) { console.error("Error processing frontmatter:", error); } } async function updateFrontMatter(plugin, file) { const modifyFrontMatter = async (frontmatter) => { frontmatter.model = plugin.settings.general.model; frontmatter.max_tokens = parseInt(plugin.settings.general.max_tokens); frontmatter.temperature = parseFloat(plugin.settings.general.temperature); frontmatter.enable_reference_current_note = plugin.settings.general.enableReferenceCurrentNote; frontmatter.prompt = plugin.settings.prompts.prompt.replace(".md", ""); frontmatter.user_name = plugin.settings.appearance.userName; frontmatter.enable_header = plugin.settings.appearance.enableHeader; frontmatter.chatbot_container_background_color = plugin.settings.appearance.chatbotContainerBackgroundColor.replace(/^#/, ""); frontmatter.message_container_background_color = plugin.settings.appearance.messageContainerBackgroundColor.replace(/^#/, ""); frontmatter.user_message_font_color = plugin.settings.appearance.userMessageFontColor.replace(/^#/, ""); frontmatter.user_message_background_color = plugin.settings.appearance.userMessageBackgroundColor.replace(/^#/, ""); frontmatter.bot_message_font_color = plugin.settings.appearance.botMessageFontColor.replace(/^#/, ""); frontmatter.chatbot_message_background_color = plugin.settings.appearance.botMessageBackgroundColor.replace(/^#/, ""); frontmatter.chatbox_font_color = plugin.settings.appearance.chatBoxFontColor.replace(/^#/, ""); frontmatter.chatbox_background_color = plugin.settings.appearance.chatBoxBackgroundColor.replace(/^#/, ""); frontmatter.bmo_generate_background_color = plugin.settings.appearance.bmoGenerateBackgroundColor.replace(/^#/, ""); frontmatter.bmo_generate_font_color = plugin.settings.appearance.bmoGenerateFontColor.replace(/^#/, ""); frontmatter.systen_role = plugin.settings.editor.systen_role; frontmatter.ollama_mirostat = parseFloat(plugin.settings.OllamaConnection.ollamaParameters.mirostat); frontmatter.ollama_mirostat_eta = parseFloat(plugin.settings.OllamaConnection.ollamaParameters.mirostat_eta); frontmatter.ollama_mirostat_tau = parseFloat(plugin.settings.OllamaConnection.ollamaParameters.mirostat_tau); frontmatter.ollama_num_ctx = parseInt(plugin.settings.OllamaConnection.ollamaParameters.num_ctx); frontmatter.ollama_num_gqa = parseInt(plugin.settings.OllamaConnection.ollamaParameters.num_gqa); frontmatter.ollama_num_thread = parseInt(plugin.settings.OllamaConnection.ollamaParameters.num_thread); frontmatter.ollama_repeat_last_n = parseInt(plugin.settings.OllamaConnection.ollamaParameters.repeat_last_n); frontmatter.ollama_repeat_penalty = parseFloat(plugin.settings.OllamaConnection.ollamaParameters.repeat_penalty); frontmatter.ollama_seed = parseInt(plugin.settings.OllamaConnection.ollamaParameters.seed); frontmatter.ollama_stop = plugin.settings.OllamaConnection.ollamaParameters.stop; frontmatter.ollama_tfs_z = parseFloat(plugin.settings.OllamaConnection.ollamaParameters.tfs_z); frontmatter.ollama_top_k = parseInt(plugin.settings.OllamaConnection.ollamaParameters.top_k); frontmatter.ollama_top_p = parseFloat(plugin.settings.OllamaConnection.ollamaParameters.top_p); frontmatter.ollama_min_p = parseFloat(plugin.settings.OllamaConnection.ollamaParameters.min_p); frontmatter.ollama_keep_alive = plugin.settings.OllamaConnection.ollamaParameters.keep_alive; }; const writeOptions = { // Specify options if needed }; try { await plugin.app.fileManager.processFrontMatter(file, modifyFrontMatter, writeOptions); updateProfile(plugin, file); } catch (error) { console.error("Error processing frontmatter:", error); } } async function updateProfile(plugin, file) { try { await plugin.app.fileManager.processFrontMatter(file, (frontmatter) => { plugin.settings.general.model = frontmatter.model || DEFAULT_SETTINGS.general.model; if (frontmatter.max_tokens) { plugin.settings.general.max_tokens = frontmatter.max_tokens.toString(); frontmatter.max_tokens = parseInt(plugin.settings.general.max_tokens); } else { plugin.settings.general.max_tokens = DEFAULT_SETTINGS.general.max_tokens; } if (frontmatter.temperature) { if (frontmatter.temperature < 0) { frontmatter.temperature = "0.00"; } else if (frontmatter.temperature > 2) { frontmatter.temperature = "2.00"; } else { plugin.settings.general.temperature = parseFloat(frontmatter.temperature).toFixed(2).toString(); frontmatter.temperature = parseFloat(plugin.settings.general.temperature); } } else { plugin.settings.general.temperature = DEFAULT_SETTINGS.general.temperature; frontmatter.temperature = DEFAULT_SETTINGS.general.temperature; } plugin.settings.general.enableReferenceCurrentNote = frontmatter.enable_reference_current_note; const referenceCurrentNoteElement = document.getElementById("referenceCurrentNote"); if (referenceCurrentNoteElement) { if (frontmatter.enable_reference_current_note === true) { referenceCurrentNoteElement.style.display = "block"; } else { referenceCurrentNoteElement.style.display = "none"; } } if (frontmatter.prompt && frontmatter.prompt !== "") { plugin.settings.prompts.prompt = frontmatter.prompt + ".md"; } else { plugin.settings.prompts.prompt = DEFAULT_SETTINGS.prompts.prompt; } if (frontmatter.user_name) { plugin.settings.appearance.userName = frontmatter.user_name.substring(0, 30); } else { plugin.settings.appearance.userName = DEFAULT_SETTINGS.appearance.userName; } frontmatter.user_name = plugin.settings.appearance.userName; const userNames = document.querySelectorAll(".userName"); userNames.forEach((userName) => { userName.textContent = plugin.settings.appearance.userName; }); const chatbotNameHeading = document.querySelector("#chatbotNameHeading"); const chatbotNames = document.querySelectorAll(".chatbotName"); if (chatbotNameHeading) { chatbotNameHeading.textContent = plugin.settings.appearance.chatbotName; } chatbotNames.forEach((chatbotName) => { chatbotName.textContent = plugin.settings.appearance.chatbotName; }); const chatbotContainer = document.querySelector(".chatbotContainer"); const messageContainer = document.querySelector("#messageContainer"); if (isValidHexColor(frontmatter.chatbot_container_background_color)) { plugin.settings.appearance.chatbotContainerBackgroundColor = "#" + frontmatter.chatbot_container_background_color.substring(0, 6); if (chatbotContainer) { chatbotContainer.style.backgroundColor = plugin.settings.appearance.chatbotContainerBackgroundColor; } } else { plugin.settings.appearance.chatbotContainerBackgroundColor = colorToHex(DEFAULT_SETTINGS.appearance.chatbotContainerBackgroundColor); frontmatter.chatbot_container_background_color = plugin.settings.appearance.chatbotContainerBackgroundColor.replace(/^#/, ""); if (chatbotContainer) { const defaultChatbotContainerBackgroundColor = getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.chatbotContainerBackgroundColor).trim(); chatbotContainer.style.backgroundColor = defaultChatbotContainerBackgroundColor; } } if (isValidHexColor(frontmatter.message_container_background_color)) { plugin.settings.appearance.messageContainerBackgroundColor = "#" + frontmatter.message_container_background_color.substring(0, 6); if (messageContainer) { messageContainer.style.backgroundColor = plugin.settings.appearance.messageContainerBackgroundColor; } } else { plugin.settings.appearance.messageContainerBackgroundColor = colorToHex(DEFAULT_SETTINGS.appearance.messageContainerBackgroundColor); frontmatter.message_container_background_color = plugin.settings.appearance.messageContainerBackgroundColor.replace(/^#/, ""); if (messageContainer) { const defaultMessageContainerBackgroundColor = getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.messageContainerBackgroundColor).trim(); messageContainer.style.backgroundColor = defaultMessageContainerBackgroundColor; } } if (isValidHexColor(frontmatter.user_message_font_color)) { plugin.settings.appearance.userMessageFontColor = "#" + frontmatter.user_message_font_color.substring(0, 6); if (messageContainer) { const userMessages = messageContainer.querySelectorAll(".userMessage"); userMessages.forEach((userMessage) => { const element = userMessage; element.style.color = plugin.settings.appearance.userMessageFontColor; }); } } else { plugin.settings.appearance.userMessageFontColor = colorToHex(DEFAULT_SETTINGS.appearance.userMessageFontColor); frontmatter.user_message_font_color = plugin.settings.appearance.userMessageFontColor.replace(/^#/, ""); if (messageContainer) { const userMessages = messageContainer.querySelectorAll(".userMessage"); userMessages.forEach((userMessage) => { const element = userMessage; const defaultUserMessageFontColor = getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.userMessageFontColor).trim(); element.style.color = defaultUserMessageFontColor; }); } } if (isValidHexColor(frontmatter.user_message_background_color)) { plugin.settings.appearance.userMessageBackgroundColor = "#" + frontmatter.user_message_background_color.substring(0, 6); if (messageContainer) { const userMessages = messageContainer.querySelectorAll(".userMessage"); userMessages.forEach((userMessage) => { const element = userMessage; element.style.backgroundColor = plugin.settings.appearance.userMessageBackgroundColor; }); } } else { plugin.settings.appearance.userMessageBackgroundColor = colorToHex(DEFAULT_SETTINGS.appearance.userMessageBackgroundColor); frontmatter.user_message_background_color = plugin.settings.appearance.userMessageBackgroundColor.replace(/^#/, ""); if (messageContainer) { const userMessages = messageContainer.querySelectorAll(".userMessage"); userMessages.forEach((userMessage) => { const element = userMessage; const defaultUserMessageBackgroundColor = getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.userMessageBackgroundColor).trim(); element.style.backgroundColor = defaultUserMessageBackgroundColor; }); } } if (isValidHexColor(frontmatter.bot_message_font_color)) { plugin.settings.appearance.botMessageFontColor = "#" + frontmatter.bot_message_font_color.substring(0, 6); if (messageContainer) { const botMessages = messageContainer.querySelectorAll(".botMessage"); botMessages.forEach((botMessage) => { const element = botMessage; element.style.color = plugin.settings.appearance.botMessageFontColor; }); } } else { plugin.settings.appearance.botMessageFontColor = colorToHex(DEFAULT_SETTINGS.appearance.botMessageFontColor); frontmatter.bot_message_font_color = plugin.settings.appearance.botMessageFontColor.replace(/^#/, ""); if (messageContainer) { const botMessages = messageContainer.querySelectorAll(".botMessage"); botMessages.forEach((botMessage) => { const element = botMessage; const defaultBotMessageFontColor = getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.botMessageFontColor).trim(); element.style.color = defaultBotMessageFontColor; }); } } if (isValidHexColor(frontmatter.chatbot_message_background_color)) { plugin.settings.appearance.botMessageBackgroundColor = "#" + frontmatter.chatbot_message_background_color.substring(0, 6); if (messageContainer) { const botMessages = messageContainer.querySelectorAll(".botMessage"); botMessages.forEach((botMessage) => { const element = botMessage; element.style.backgroundColor = plugin.settings.appearance.botMessageBackgroundColor; }); } } else { plugin.settings.appearance.botMessageBackgroundColor = colorToHex(DEFAULT_SETTINGS.appearance.botMessageBackgroundColor); frontmatter.chatbot_message_background_color = plugin.settings.appearance.botMessageBackgroundColor.replace(/^#/, ""); if (messageContainer) { const botMessages = messageContainer.querySelectorAll(".botMessage"); botMessages.forEach((botMessage) => { const element = botMessage; const defaultBotMessageBackgroundColor = getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.botMessageBackgroundColor).trim(); element.style.backgroundColor = defaultBotMessageBackgroundColor; }); } } if (isValidHexColor(frontmatter.chatbox_font_color)) { plugin.settings.appearance.chatBoxFontColor = "#" + frontmatter.chatbox_font_color.substring(0, 6); const textarea = document.querySelector(".chatbox textarea"); if (textarea) { textarea.style.color = plugin.settings.appearance.chatBoxFontColor; const style = document.createElement("style"); style.textContent = ` .chatbox textarea::placeholder { color: ${plugin.settings.appearance.chatBoxFontColor} !important; } `; textarea.appendChild(style); } } else { plugin.settings.appearance.chatBoxFontColor = colorToHex(DEFAULT_SETTINGS.appearance.chatBoxFontColor); frontmatter.chatbox_font_color = plugin.settings.appearance.chatBoxFontColor.replace(/^#/, ""); const textarea = document.querySelector(".chatbox textarea"); const defaultChatBoxFontColor = getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.chatBoxFontColor).trim(); if (textarea) { textarea.style.color = DEFAULT_SETTINGS.appearance.chatBoxFontColor; const style = document.createElement("style"); style.textContent = ` .chatbox textarea::placeholder { color: ${defaultChatBoxFontColor} !important; } `; textarea.appendChild(style); } } if (isValidHexColor(frontmatter.chatbox_background_color)) { plugin.settings.appearance.chatBoxBackgroundColor = "#" + frontmatter.chatbox_background_color.substring(0, 6); if (messageContainer) { const chatbox = document.querySelector(".chatbox"); if (chatbox) { const element = chatbox; element.style.backgroundColor = plugin.settings.appearance.chatBoxBackgroundColor; element.style.borderColor = plugin.settings.appearance.chatBoxBackgroundColor; } const textarea = document.querySelector(".chatbox textarea"); if (textarea) { const element = textarea; element.style.backgroundColor = plugin.settings.appearance.chatBoxBackgroundColor; element.style.borderColor = plugin.settings.appearance.chatBoxBackgroundColor; } const submitButton = document.querySelector(".chatbox .submit-button"); if (submitButton) { const element = submitButton; element.style.backgroundColor = plugin.settings.appearance.chatBoxBackgroundColor; element.style.borderColor = plugin.settings.appearance.chatBoxBackgroundColor; } } } else { plugin.settings.appearance.chatBoxBackgroundColor = DEFAULT_SETTINGS.appearance.chatBoxBackgroundColor; frontmatter.chatbox_background_color = DEFAULT_SETTINGS.appearance.chatBoxBackgroundColor.replace(/^#/, ""); const defaultChatBoxBackgroundColor = getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.chatBoxBackgroundColor).trim(); if (messageContainer) { const chatbox = document.querySelector(".chatbox"); if (chatbox) { const element = chatbox; element.style.backgroundColor = defaultChatBoxBackgroundColor; element.style.borderColor = defaultChatBoxBackgroundColor; } const textarea = document.querySelector(".chatbox textarea"); if (textarea) { const element = textarea; element.style.backgroundColor = defaultChatBoxBackgroundColor; element.style.borderColor = defaultChatBoxBackgroundColor; } const submitButton = document.querySelector(".chatbox .submit-button"); if (submitButton) { const element = submitButton; element.style.backgroundColor = defaultChatBoxBackgroundColor; element.style.borderColor = defaultChatBoxBackgroundColor; } } } if (isValidHexColor(frontmatter.bmo_generate_background_color)) { plugin.settings.appearance.bmoGenerateBackgroundColor = "#" + frontmatter.bmo_generate_background_color.substring(0, 6); const containers = document.querySelectorAll(".bmoCodeBlockContainer"); containers.forEach((container) => { const element = container; element.style.backgroundColor = plugin.settings.appearance.bmoGenerateBackgroundColor; }); } else { plugin.settings.appearance.bmoGenerateBackgroundColor = colorToHex(DEFAULT_SETTINGS.appearance.bmoGenerateBackgroundColor); frontmatter.bmo_generate_background_color = plugin.settings.appearance.bmoGenerateBackgroundColor.replace(/^#/, ""); const containers = document.querySelectorAll(".bmoCodeBlockContainer"); containers.forEach((container) => { const element = container; const defaultBMOGenerateBackgroundColor = getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.bmoGenerateBackgroundColor).trim(); element.style.backgroundColor = defaultBMOGenerateBackgroundColor; }); } if (isValidHexColor(frontmatter.bmo_generate_font_color)) { plugin.settings.appearance.bmoGenerateFontColor = "#" + frontmatter.bmo_generate_font_color.substring(0, 6); const containers = document.querySelectorAll(".bmoCodeBlockContent"); containers.forEach((container) => { const element = container; element.style.color = plugin.settings.appearance.bmoGenerateFontColor; }); } else { plugin.settings.appearance.bmoGenerateFontColor = colorToHex(DEFAULT_SETTINGS.appearance.bmoGenerateFontColor); frontmatter.bmo_generate_font_color = plugin.settings.appearance.bmoGenerateFontColor.replace(/^#/, ""); const containers = document.querySelectorAll(".bmoCodeBlockContent"); containers.forEach((container) => { const element = container; const defaultBMOGenerateFontColor = getComputedStyle(document.body).getPropertyValue(DEFAULT_SETTINGS.appearance.bmoGenerateFontColor).trim(); element.style.color = defaultBMOGenerateFontColor; }); } plugin.settings.editor.systen_role = frontmatter.systen_role; plugin.settings.appearance.enableHeader = frontmatter.enable_header; if (frontmatter.enable_header === true) { const header = document.querySelector("#header"); if (header) { header.style.display = "block"; referenceCurrentNoteElement.style.margin = "-0.5rem 0 0.5rem 0"; } } else { const header = document.querySelector("#header"); const messageContainer2 = document.querySelector("#messageContainer"); if (header) { header.style.display = "none"; messageContainer2.style.maxHeight = "calc(100% - 60px)"; referenceCurrentNoteElement.style.margin = "0.5rem 0 0.5rem 0"; } } const intValue = parseInt(frontmatter.ollama_mirostat, 10); if (isNaN(intValue)) { plugin.settings.OllamaConnection.ollamaParameters.mirostat = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.mirostat; frontmatter.ollama_mirostat = plugin.settings.OllamaConnection.ollamaParameters.mirostat; } else { plugin.settings.OllamaConnection.ollamaParameters.mirostat = intValue.toString(); frontmatter.ollama_mirostat = intValue; } if (isNaN(parseFloat(frontmatter.ollama_mirostat_eta))) { plugin.settings.OllamaConnection.ollamaParameters.mirostat_eta = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.mirostat_eta; frontmatter.ollama_mirostat_eta = plugin.settings.OllamaConnection.ollamaParameters.mirostat_eta; } else { plugin.settings.OllamaConnection.ollamaParameters.mirostat_eta = parseFloat(frontmatter.ollama_mirostat_eta).toFixed(2).toString(); frontmatter.ollama_mirostat_eta = parseFloat(plugin.settings.OllamaConnection.ollamaParameters.mirostat_eta); } if (isNaN(parseFloat(frontmatter.ollama_mirostat_tau))) { plugin.settings.OllamaConnection.ollamaParameters.mirostat_tau = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.mirostat_tau; frontmatter.ollama_mirostat_tau = plugin.settings.OllamaConnection.ollamaParameters.mirostat_tau; } else { plugin.settings.OllamaConnection.ollamaParameters.mirostat_tau = parseFloat(frontmatter.ollama_mirostat_tau).toFixed(2).toString(); frontmatter.ollama_mirostat_tau = parseFloat(plugin.settings.OllamaConnection.ollamaParameters.mirostat_tau); } if (isNaN(parseInt(frontmatter.ollama_num_ctx))) { plugin.settings.OllamaConnection.ollamaParameters.num_ctx = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.num_ctx; frontmatter.ollama_num_ctx = plugin.settings.OllamaConnection.ollamaParameters.num_ctx; } else { plugin.settings.OllamaConnection.ollamaParameters.num_ctx = parseInt(frontmatter.ollama_num_ctx).toString(); frontmatter.ollama_num_ctx = parseInt(plugin.settings.OllamaConnection.ollamaParameters.num_ctx); } if (isNaN(parseInt(frontmatter.ollama_num_gqa))) { plugin.settings.OllamaConnection.ollamaParameters.num_gqa = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.num_gqa; } else { plugin.settings.OllamaConnection.ollamaParameters.num_gqa = parseInt(frontmatter.ollama_num_gqa).toString(); frontmatter.ollama_num_gqa = parseInt(plugin.settings.OllamaConnection.ollamaParameters.num_gqa); } if (isNaN(parseInt(frontmatter.ollama_num_thread))) { plugin.settings.OllamaConnection.ollamaParameters.num_thread = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.num_thread; } else { plugin.settings.OllamaConnection.ollamaParameters.num_thread = parseInt(frontmatter.ollama_num_thread).toString(); frontmatter.ollama_num_thread = parseInt(plugin.settings.OllamaConnection.ollamaParameters.num_thread); } if (isNaN(parseInt(frontmatter.ollama_repeat_last_n))) { plugin.settings.OllamaConnection.ollamaParameters.repeat_last_n = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.repeat_last_n; frontmatter.ollama_repeat_last_n = plugin.settings.OllamaConnection.ollamaParameters.repeat_last_n; } else { plugin.settings.OllamaConnection.ollamaParameters.repeat_last_n = parseInt(frontmatter.ollama_repeat_last_n).toString(); frontmatter.ollama_repeat_last_n = parseInt(plugin.settings.OllamaConnection.ollamaParameters.repeat_last_n); } if (isNaN(parseFloat(frontmatter.ollama_repeat_penalty))) { plugin.settings.OllamaConnection.ollamaParameters.repeat_penalty = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.repeat_penalty; frontmatter.ollama_repeat_penalty = plugin.settings.OllamaConnection.ollamaParameters.repeat_penalty; } else { plugin.settings.OllamaConnection.ollamaParameters.repeat_penalty = parseFloat(frontmatter.ollama_repeat_penalty).toFixed(2).toString(); frontmatter.ollama_repeat_penalty = parseFloat(plugin.settings.OllamaConnection.ollamaParameters.repeat_penalty); } if (isNaN(parseInt(frontmatter.ollama_seed))) { plugin.settings.OllamaConnection.ollamaParameters.seed = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.seed; } else { plugin.settings.OllamaConnection.ollamaParameters.seed = parseInt(frontmatter.ollama_seed).toString(); frontmatter.ollama_seed = parseInt(plugin.settings.OllamaConnection.ollamaParameters.seed); } plugin.settings.OllamaConnection.ollamaParameters.stop = frontmatter.ollama_stop; if (isNaN(parseFloat(frontmatter.ollama_tfs_z))) { plugin.settings.OllamaConnection.ollamaParameters.tfs_z = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.tfs_z; frontmatter.ollama_tfs_z = plugin.settings.OllamaConnection.ollamaParameters.tfs_z; } else { plugin.settings.OllamaConnection.ollamaParameters.tfs_z = parseFloat(frontmatter.ollama_tfs_z).toFixed(2).toString(); frontmatter.ollama_tfs_z = parseFloat(plugin.settings.OllamaConnection.ollamaParameters.tfs_z); } if (isNaN(parseInt(frontmatter.ollama_top_k))) { plugin.settings.OllamaConnection.ollamaParameters.top_k = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.top_k; frontmatter.ollama_top_k = plugin.settings.OllamaConnection.ollamaParameters.top_k; } else { plugin.settings.OllamaConnection.ollamaParameters.top_k = parseInt(frontmatter.ollama_top_k).toString(); frontmatter.ollama_top_k = parseInt(plugin.settings.OllamaConnection.ollamaParameters.top_k); } if (isNaN(parseInt(frontmatter.ollama_top_p))) { plugin.settings.OllamaConnection.ollamaParameters.top_p = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.top_p; frontmatter.ollama_top_p = plugin.settings.OllamaConnection.ollamaParameters.top_p; } else { plugin.settings.OllamaConnection.ollamaParameters.top_p = parseFloat(frontmatter.ollama_top_p).toFixed(2).toString(); frontmatter.ollama_top_p = parseFloat(plugin.settings.OllamaConnection.ollamaParameters.top_p); } if (isNaN(parseInt(frontmatter.ollama_min_p))) { plugin.settings.OllamaConnection.ollamaParameters.min_p = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.min_p; frontmatter.ollama_min_p = plugin.settings.OllamaConnection.ollamaParameters.min_p; } else { plugin.settings.OllamaConnection.ollamaParameters.min_p = parseFloat(frontmatter.ollama_min_p).toFixed(2).toString(); frontmatter.ollama_min_p = parseFloat(plugin.settings.OllamaConnection.ollamaParameters.min_p); } const match = String(frontmatter.ollama_keep_alive).match(/^(-?\d+)(m|hr|h)?$/); if (match) { const num = parseInt(match[1]); const unit = match[2]; let seconds; if (unit === "m") { seconds = num * 60; } else if (unit === "hr" || unit === "h") { seconds = num * 3600; } else { seconds = num; } plugin.settings.OllamaConnection.ollamaParameters.keep_alive = seconds.toString(); frontmatter.ollama_keep_alive = plugin.settings.OllamaConnection.ollamaParameters.keep_alive; } else { plugin.settings.OllamaConnection.ollamaParameters.keep_alive = DEFAULT_SETTINGS.OllamaConnection.ollamaParameters.keep_alive; frontmatter.ollama_keep_alive = plugin.settings.OllamaConnection.ollamaParameters.keep_alive; } }); } catch (error) { console.error("Error processing frontmatter:", error); } } /* nosourcemap */