mirror of
https://github.com/zsviczian/obsidian-excalidraw-plugin.git
synced 2025-08-06 05:46:28 +00:00
2.0.4
This commit is contained in:
129
src/utils/AIUtils.ts
Normal file
129
src/utils/AIUtils.ts
Normal file
@@ -0,0 +1,129 @@
|
||||
import { Notice, RequestUrlResponse, requestUrl } from "obsidian";
|
||||
import ExcalidrawPlugin from "src/main";
|
||||
|
||||
type MessageContent =
|
||||
| string
|
||||
| (string | { type: "image_url"; image_url: string })[];
|
||||
|
||||
export type GPTCompletionRequest = {
|
||||
model: string;
|
||||
messages: {
|
||||
role: "system" | "user" | "assistant" | "function";
|
||||
content: MessageContent;
|
||||
name?: string | undefined;
|
||||
}[];
|
||||
functions?: any[] | undefined;
|
||||
function_call?: any | undefined;
|
||||
stream?: boolean | undefined;
|
||||
temperature?: number | undefined;
|
||||
top_p?: number | undefined;
|
||||
max_tokens?: number | undefined;
|
||||
n?: number | undefined;
|
||||
best_of?: number | undefined;
|
||||
frequency_penalty?: number | undefined;
|
||||
presence_penalty?: number | undefined;
|
||||
logit_bias?:
|
||||
| {
|
||||
[x: string]: number;
|
||||
}
|
||||
| undefined;
|
||||
stop?: (string[] | string) | undefined;
|
||||
};
|
||||
|
||||
export type AIRequest = {
|
||||
image?: string;
|
||||
text?: string;
|
||||
instruction?: string;
|
||||
systemPrompt?: string;
|
||||
};
|
||||
|
||||
export const postOpenAI = async (request: AIRequest) : Promise<RequestUrlResponse> => {
|
||||
const plugin: ExcalidrawPlugin = window.ExcalidrawAutomate.plugin;
|
||||
const { openAIAPIToken, openAIDefaultTextModel, openAIDefaultVisionModel} = plugin.settings;
|
||||
const { image, text, instruction, systemPrompt } = request;
|
||||
const requestType = image ? "image" : "text";
|
||||
let body: GPTCompletionRequest;
|
||||
|
||||
if(openAIAPIToken === "") {
|
||||
new Notice("OpenAI API Token is not set. Please set it in plugin settings.");
|
||||
return null;
|
||||
}
|
||||
switch (requestType) {
|
||||
case "text":
|
||||
body = {
|
||||
model: openAIDefaultTextModel,
|
||||
max_tokens: 4096,
|
||||
messages: [
|
||||
...(systemPrompt ? [{role: "system" as const,content: systemPrompt}] : []),
|
||||
{
|
||||
role: "user",
|
||||
content: text,
|
||||
},
|
||||
...(instruction ? [{role: "user" as const,content: instruction}] : [])
|
||||
],
|
||||
};
|
||||
break;
|
||||
case "image":
|
||||
body = {
|
||||
model: openAIDefaultVisionModel,
|
||||
max_tokens: 4096,
|
||||
messages: [
|
||||
...(systemPrompt ? [{role: "system" as const,content: [systemPrompt]}] : []),
|
||||
{
|
||||
role: "user",
|
||||
content: [
|
||||
{
|
||||
type: "image_url",
|
||||
image_url: image,
|
||||
},
|
||||
...(instruction ? [instruction] : []), //"Turn this into a single html file using tailwind.",
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
const resp = await requestUrl ({
|
||||
url: "https://api.openai.com/v1/chat/completions",
|
||||
method: "post",
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify(body),
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${openAIAPIToken}`,
|
||||
},
|
||||
throw: false
|
||||
});
|
||||
return resp;
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Grabs the codeblock contents from the supplied markdown string.
|
||||
* @param markdown
|
||||
* @param codeblockType
|
||||
* @returns an array of dictionaries with the codeblock contents and type
|
||||
*/
|
||||
export const extractCodeBlocks = (markdown: string): { data: string, type: string }[] => {
|
||||
if (!markdown) return [];
|
||||
|
||||
markdown = markdown.replaceAll("\r\n", "\n").replaceAll("\r", "\n");
|
||||
const result: { data: string, type: string }[] = [];
|
||||
const regex = /```([a-zA-Z0-9]*)\n([\s\S]+?)```/g;
|
||||
let match;
|
||||
|
||||
while ((match = regex.exec(markdown)) !== null) {
|
||||
const codeblockType = match[1]??"";
|
||||
const codeblockString = match[2].trim();
|
||||
result.push({ data: codeblockString, type: codeblockType });
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -11,6 +11,7 @@ container.appendChild(node.contentEl)
|
||||
import { TFile, WorkspaceLeaf, WorkspaceSplit } from "obsidian";
|
||||
import ExcalidrawView from "src/ExcalidrawView";
|
||||
import { getContainerForDocument, ConstructableWorkspaceSplit, isObsidianThemeDark } from "./ObsidianUtils";
|
||||
import { CustomMutationObserver, isDebugMode } from "./DebugHelper";
|
||||
|
||||
declare module "obsidian" {
|
||||
interface Workspace {
|
||||
@@ -94,8 +95,8 @@ export class CanvasNodeFactory {
|
||||
if (!node.child.editor?.containerEl?.parentElement?.parentElement) return;
|
||||
node.child.editor.containerEl.parentElement.parentElement.classList.remove(obsidianTheme);
|
||||
node.child.editor.containerEl.parentElement.parentElement.classList.add(theme);
|
||||
|
||||
const observer = new MutationObserver((mutationsList) => {
|
||||
|
||||
const nodeObserverFn: MutationCallback = (mutationsList) => {
|
||||
for (const mutation of mutationsList) {
|
||||
if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
|
||||
const targetElement = mutation.target as HTMLElement;
|
||||
@@ -105,7 +106,10 @@ export class CanvasNodeFactory {
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
const observer = isDebugMode
|
||||
? new CustomMutationObserver(nodeObserverFn, "CanvasNodeFactory")
|
||||
: new MutationObserver(nodeObserverFn);
|
||||
|
||||
observer.observe(node.child.editor.containerEl.parentElement.parentElement, { attributes: true });
|
||||
})();
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { NonDeletedExcalidrawElement } from "@zsviczian/excalidraw/types/element/types";
|
||||
import { DEVICE, REG_LINKINDEX_INVALIDCHARS } from "src/constants";
|
||||
import { DEVICE, REG_LINKINDEX_INVALIDCHARS } from "src/constants/constants";
|
||||
import { getParentOfClass } from "./ObsidianUtils";
|
||||
import { TFile, WorkspaceLeaf } from "obsidian";
|
||||
import { getLinkParts } from "./Utils";
|
||||
import ExcalidrawView from "src/ExcalidrawView";
|
||||
|
||||
export const useDefaultExcalidrawFrame = (element: NonDeletedExcalidrawElement) => {
|
||||
return !element.link.startsWith("["); // && !element.link.match(TWITTER_REG);
|
||||
return !(element.link.startsWith("[") || element.link.startsWith("file:") || element.link.startsWith("data:")); // && !element.link.match(TWITTER_REG);
|
||||
}
|
||||
|
||||
export const leafMap = new Map<string, WorkspaceLeaf>();
|
||||
|
||||
38
src/utils/DebugHelper.ts
Normal file
38
src/utils/DebugHelper.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
export const isDebugMode = false;
|
||||
export const durationTreshold = 0.05; //ms
|
||||
|
||||
export class CustomMutationObserver {
|
||||
private originalCallback: MutationCallback;
|
||||
private observer: MutationObserver | null;
|
||||
private name: string;
|
||||
|
||||
constructor(callback: MutationCallback, name: string) {
|
||||
this.originalCallback = callback;
|
||||
this.observer = null;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
observe(target: Node, options: MutationObserverInit) {
|
||||
const wrappedCallback: MutationCallback = async (mutationsList, observer) => {
|
||||
const startTime = performance.now(); // Get start time
|
||||
await this.originalCallback(mutationsList, observer); // Invoke the original callback
|
||||
const endTime = performance.now(); // Get end time
|
||||
const executionTime = endTime - startTime;
|
||||
if (executionTime > durationTreshold) {
|
||||
console.log(`Excalidraw ${this.name} MutationObserver callback took ${executionTime}ms to execute`);
|
||||
}
|
||||
};
|
||||
|
||||
this.observer = new MutationObserver(wrappedCallback);
|
||||
|
||||
// Start observing with the modified callback
|
||||
this.observer.observe(target, options);
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
if (this.observer) {
|
||||
this.observer.disconnect();
|
||||
this.observer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import { DynamicStyle } from "src/types";
|
||||
import { cloneElement } from "src/ExcalidrawAutomate";
|
||||
import { ExcalidrawFrameElement } from "@zsviczian/excalidraw/types/element/types";
|
||||
import { addAppendUpdateCustomData } from "./Utils";
|
||||
import { mutateElement } from "src/constants";
|
||||
import { mutateElement } from "src/constants/constants";
|
||||
|
||||
export const setDynamicStyle = (
|
||||
ea: ExcalidrawAutomate,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
import { MAX_IMAGE_SIZE, IMAGE_TYPES } from "src/constants";
|
||||
import { MAX_IMAGE_SIZE, IMAGE_TYPES } from "src/constants/constants";
|
||||
import { TFile } from "obsidian";
|
||||
import { ExcalidrawAutomate } from "src/ExcalidrawAutomate";
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { DataURL } from "@zsviczian/excalidraw/types/types";
|
||||
import { loadPdfJs, normalizePath, Notice, requestUrl, RequestUrlResponse, TAbstractFile, TFile, TFolder, Vault } from "obsidian";
|
||||
import { URLFETCHTIMEOUT } from "src/constants";
|
||||
import { URLFETCHTIMEOUT } from "src/constants/constants";
|
||||
import { MimeType } from "src/EmbeddedFileLoader";
|
||||
import { ExcalidrawSettings } from "src/settings";
|
||||
import { errorlog, getDataURL } from "./Utils";
|
||||
@@ -134,7 +134,7 @@ export function getEmbedFilename(
|
||||
* Open or create a folderpath if it does not exist
|
||||
* @param folderpath
|
||||
*/
|
||||
export async function checkAndCreateFolder(folderpath: string) {
|
||||
export async function checkAndCreateFolder(folderpath: string):Promise<TFolder> {
|
||||
const vault = app.vault;
|
||||
folderpath = normalizePath(folderpath);
|
||||
//https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/658
|
||||
@@ -146,7 +146,7 @@ export async function checkAndCreateFolder(folderpath: string) {
|
||||
if (folder && folder instanceof TFile) {
|
||||
new Notice(`The folder cannot be created because it already exists as a file: ${folderpath}.`)
|
||||
}
|
||||
await vault.createFolder(folderpath);
|
||||
return await vault.createFolder(folderpath);
|
||||
}
|
||||
|
||||
export const getURLImageExtension = (url: string):string => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { DEVICE, isDarwin } from "src/constants";
|
||||
import { DEVICE, isDarwin } from "src/constants/constants";
|
||||
export type ModifierKeys = {shiftKey:boolean, ctrlKey: boolean, metaKey: boolean, altKey: boolean};
|
||||
export type KeyEvent = PointerEvent | MouseEvent | KeyboardEvent | React.DragEvent | React.PointerEvent | React.MouseEvent | ModifierKeys;
|
||||
export type PaneTarget = "active-pane"|"new-pane"|"popout-window"|"new-tab"|"md-properties";
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
import ExcalidrawPlugin from "../main";
|
||||
import { checkAndCreateFolder, splitFolderAndFilename } from "./FileUtils";
|
||||
import { linkClickModifierType, ModifierKeys } from "./ModifierkeyHelper";
|
||||
import { REG_BLOCK_REF_CLEAN, REG_SECTION_REF_CLEAN } from "src/constants";
|
||||
import { REG_BLOCK_REF_CLEAN, REG_SECTION_REF_CLEAN } from "src/constants/constants";
|
||||
|
||||
export const getParentOfClass = (element: Element, cssClass: string):HTMLElement | null => {
|
||||
let parent = element.parentElement;
|
||||
|
||||
@@ -11,6 +11,8 @@ export class StylesManager {
|
||||
private styleDark: string;
|
||||
private plugin: ExcalidrawPlugin;
|
||||
|
||||
|
||||
|
||||
constructor(plugin: ExcalidrawPlugin) {
|
||||
this.plugin = plugin;
|
||||
plugin.app.workspace.onLayoutReady(async () => {
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
ASSISTANT_FONT,
|
||||
CASCADIA_FONT,
|
||||
VIRGIL_FONT,
|
||||
} from "src/constFonts";
|
||||
} from "src/constants/constFonts";
|
||||
import {
|
||||
FRONTMATTER_KEY_EXPORT_DARK,
|
||||
FRONTMATTER_KEY_EXPORT_TRANSPARENT,
|
||||
@@ -23,7 +23,7 @@ import {
|
||||
exportToSvg,
|
||||
exportToBlob,
|
||||
IMAGE_TYPES
|
||||
} from "../constants";
|
||||
} from "../constants/constants";
|
||||
import ExcalidrawPlugin from "../main";
|
||||
import { ExcalidrawElement } from "@zsviczian/excalidraw/types/element/types";
|
||||
import { ExportSettings } from "../ExcalidrawView";
|
||||
|
||||
Reference in New Issue
Block a user