From c4359cf20c45fa921e7a8e3e5df1b889ab6a2241 Mon Sep 17 00:00:00 2001 From: Vanessa Date: Wed, 8 Mar 2023 21:57:57 +0800 Subject: [PATCH] :sparkles: https://github.com/siyuan-note/siyuan/issues/7566 --- app/src/ai/actions.ts | 85 +++++++++++++++++++++++++++++++++ app/src/ai/chat.ts | 39 +++++++++++++++ app/src/protyle/gutter/index.ts | 3 ++ app/src/protyle/hint/index.ts | 35 +------------- 4 files changed, 129 insertions(+), 33 deletions(-) create mode 100644 app/src/ai/actions.ts create mode 100644 app/src/ai/chat.ts diff --git a/app/src/ai/actions.ts b/app/src/ai/actions.ts new file mode 100644 index 000000000..a12dcc2c6 --- /dev/null +++ b/app/src/ai/actions.ts @@ -0,0 +1,85 @@ +import {MenuItem} from "../menus/Menu"; +import {fetchPost} from "../util/fetch"; +import {focusByRange} from "../protyle/util/selection"; +import {insertHTML} from "../protyle/util/insertHTML"; + +export const AIActions = (elements: Element[], protyle: IProtyle) => { + const ids: string[] = [] + elements.forEach(item => { + ids.push(item.getAttribute("data-node-id")) + }) + window.siyuan.menus.menu.append(new MenuItem({ + icon: "iconRefresh", + label: window.siyuan.languages.ai, + type: "submenu", + submenu: [{ + label: window.siyuan.languages.aiContinueWrite, + click() { + fetchPost("/api/ai/chatGPTWithAction", {ids, action: "Continue writing"}, (response) => { + focusByRange(protyle.toolbar.range); + insertHTML(response.data, protyle, true); + }); + } + }, { + label: window.siyuan.languages.aiTranslate, + type: "submenu", + submenu: [{ + label: window.siyuan.languages.aiTranslate_zh_CN, + click() { + fetchPost("/api/ai/chatGPTWithAction", {ids, action: "Translate"}, (response) => { + focusByRange(protyle.toolbar.range); + insertHTML(response.data, protyle, true); + }); + } + }, { + label: window.siyuan.languages.aiTranslate_ja_JP, + click() { + fetchPost("/api/ai/chatGPTWithAction", {ids, action: "Translate"}, (response) => { + focusByRange(protyle.toolbar.range); + insertHTML(response.data, protyle, true); + }); + } + }, { + label: window.siyuan.languages.aiTranslate_ko_KR, + click() { + fetchPost("/api/ai/chatGPTWithAction", {ids, action: "Translate"}, (response) => { + focusByRange(protyle.toolbar.range); + insertHTML(response.data, protyle, true); + }); + } + }, { + label: window.siyuan.languages.aiTranslate_en_US, + click() { + fetchPost("/api/ai/chatGPTWithAction", {ids, action: "Translate"}, (response) => { + focusByRange(protyle.toolbar.range); + insertHTML(response.data, protyle, true); + }); + } + }, { + label: window.siyuan.languages.aiTranslate_es_ES, + click() { + fetchPost("/api/ai/chatGPTWithAction", {ids, action: "Translate"}, (response) => { + focusByRange(protyle.toolbar.range); + insertHTML(response.data, protyle, true); + }); + } + }, { + label: window.siyuan.languages.aiTranslate_fr_FR, + click() { + fetchPost("/api/ai/chatGPTWithAction", {ids, action: "Translate"}, (response) => { + focusByRange(protyle.toolbar.range); + insertHTML(response.data, protyle, true); + }); + } + }, { + label: window.siyuan.languages.aiTranslate_de_DE, + click() { + fetchPost("/api/ai/chatGPTWithAction", {ids, action: "Translate"}, (response) => { + focusByRange(protyle.toolbar.range); + insertHTML(response.data, protyle, true); + }); + } + }] + }] + }).element); +} diff --git a/app/src/ai/chat.ts b/app/src/ai/chat.ts new file mode 100644 index 000000000..fa481dfac --- /dev/null +++ b/app/src/ai/chat.ts @@ -0,0 +1,39 @@ +import {Dialog} from "../dialog"; +import {isMobile} from "../util/functions"; +import {fetchPost} from "../util/fetch"; +import {focusByRange} from "../protyle/util/selection"; +import {insertHTML} from "../protyle/util/insertHTML"; + +export const AIChat = (protyle:IProtyle) => { + const dialog = new Dialog({ + title: "AI Chat", + content: `
+
+
+ +
`, + width: isMobile() ? "80vw" : "520px", + }); + const inputElement = dialog.element.querySelector("input") as HTMLInputElement; + const btnsElement = dialog.element.querySelectorAll(".b3-button"); + dialog.bindInput(inputElement, () => { + (btnsElement[1] as HTMLButtonElement).click(); + }); + inputElement.focus(); + btnsElement[0].addEventListener("click", () => { + dialog.destroy(); + }); + btnsElement[1].addEventListener("click", () => { + fetchPost("/api/ai/chatGPT", { + msg: inputElement.value, + }, (response) => { + dialog.destroy(); + focusByRange(protyle.toolbar.range); + let respContent = ""; + if (response.data && "" !== response.data) { + respContent = "\n\n" + response.data; + } + insertHTML(`${inputElement.value}${respContent}`, protyle, true); + }); + }); +} diff --git a/app/src/protyle/gutter/index.ts b/app/src/protyle/gutter/index.ts index 19dabf2a8..cb190c6cd 100644 --- a/app/src/protyle/gutter/index.ts +++ b/app/src/protyle/gutter/index.ts @@ -35,6 +35,7 @@ import {hintMoveBlock} from "../hint/extend"; import {makeCard, quickMakeCard} from "../../card/makeCard"; import {transferBlockRef} from "../../menus/block"; import {isMobile} from "../../util/functions"; +import {AIActions} from "../../ai/actions"; export class Gutter { public element: HTMLElement; @@ -433,6 +434,7 @@ export class Gutter { return true; } }); + AIActions(selectsElement, protyle); if (!isList && !protyle.disabled) { const turnIntoSubmenu: IMenu[] = []; if (isContinue) { @@ -732,6 +734,7 @@ export class Gutter { hideElements(["select"], protyle); nodeElement.classList.add("protyle-wysiwyg--select"); countBlockWord([id], protyle.block.rootID); + AIActions([nodeElement], protyle); // "heading1-6", "list", "ordered-list", "check", "quote", "code", "table", "line", "math", "paragraph" if (type === "NodeParagraph" && !protyle.disabled) { turnIntoSubmenu.push(this.turnsIntoOne({ diff --git a/app/src/protyle/hint/index.ts b/app/src/protyle/hint/index.ts index 5b58a43e8..8708f84c2 100644 --- a/app/src/protyle/hint/index.ts +++ b/app/src/protyle/hint/index.ts @@ -29,8 +29,7 @@ import {openFileById} from "../../editor/util"; import {openMobileFileById} from "../../mobile/editor"; import {getIconByType} from "../../editor/getIcon"; import {processRender} from "../util/processCode"; -import {Dialog} from "../../dialog"; -import {isMobile} from "../../util/functions"; +import {AIChat} from "../../ai/chat"; export class Hint { public timeId: number; @@ -552,37 +551,7 @@ ${unicode2Emoji(emoji.unicode, true)}`; }); return; } else if (value === Constants.ZWSP + 5) { - const dialog = new Dialog({ - title: "AI Chat", - content: `
-
-
- -
`, - width: isMobile() ? "80vw" : "520px", - }); - const inputElement = dialog.element.querySelector("input") as HTMLInputElement; - const btnsElement = dialog.element.querySelectorAll(".b3-button"); - dialog.bindInput(inputElement, () => { - (btnsElement[1] as HTMLButtonElement).click(); - }); - inputElement.focus(); - btnsElement[0].addEventListener("click", () => { - dialog.destroy(); - }); - btnsElement[1].addEventListener("click", () => { - fetchPost("/api/ai/chatGPT", { - msg: inputElement.value, - }, (response) => { - dialog.destroy(); - focusByRange(protyle.toolbar.range); - let respContent = ""; - if (response.data && "" !== response.data) { - respContent = "\n\n" + response.data; - } - insertHTML(`${inputElement.value}${respContent}`, protyle, true); - }); - }); + AIChat(protyle); return; } else if (Constants.INLINE_TYPE.includes(value)) { range.deleteContents();