From 07babda68e3ca867b125b76226329aa8f1fcd8a2 Mon Sep 17 00:00:00 2001 From: fofolee Date: Sat, 15 Mar 2025 14:12:58 +0800 Subject: [PATCH] =?UTF-8?q?askAi=E8=BF=9B=E5=BA=A6=E6=9D=A1=E6=94=AF?= =?UTF-8?q?=E6=8C=81markdown?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 31 -------- package.json | 1 - plugin/lib/ai.js | 18 ++++- plugin/lib/dialog/style.css | 84 +++++++++++++++++++- plugin/package-lock.json | 31 ++++++++ plugin/package.json | 1 + plugin/preload.js | 2 + src/components/ai/AIChatHistory.vue | 11 +-- src/components/card/layouts/DenseLayout.vue | 3 +- src/components/card/layouts/ListLayout.vue | 3 +- src/components/card/layouts/MiniLayout.vue | 3 +- src/components/quickcommandUI/ConfirmBox.vue | 5 +- src/css/markdown.css | 5 ++ 13 files changed, 146 insertions(+), 52 deletions(-) diff --git a/package-lock.json b/package-lock.json index c507db2..083c2e2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,6 @@ "@quasar/extras": "^1.14.0", "core-js": "^3.6.5", "croner": "^4.3.9", - "dompurify": "^3.2.4", "monaco-editor": "^0.33.0", "monaco-editor-webpack-plugin": "^7.0.1", "picture-compressor": "^1.1.0", @@ -2487,13 +2486,6 @@ "@types/node": "*" } }, - "node_modules/@types/trusted-types": { - "version": "2.0.7", - "resolved": "https://registry.npmmirror.com/@types/trusted-types/-/trusted-types-2.0.7.tgz", - "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", - "license": "MIT", - "optional": true - }, "node_modules/@types/webpack-bundle-analyzer": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/@types/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.7.0.tgz", @@ -4631,15 +4623,6 @@ "url": "https://github.com/fb55/domhandler?sponsor=1" } }, - "node_modules/dompurify": { - "version": "3.2.4", - "resolved": "https://registry.npmmirror.com/dompurify/-/dompurify-3.2.4.tgz", - "integrity": "sha512-ysFSFEDVduQpyhzAob/kkuJjf5zWkZD8/A9ywSp1byueyuCfHamrCBa14/Oc2iiB0e51B+NpxSl5gmzn+Ms/mg==", - "license": "(MPL-2.0 OR Apache-2.0)", - "optionalDependencies": { - "@types/trusted-types": "^2.0.7" - } - }, "node_modules/domutils": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", @@ -13066,12 +13049,6 @@ "@types/node": "*" } }, - "@types/trusted-types": { - "version": "2.0.7", - "resolved": "https://registry.npmmirror.com/@types/trusted-types/-/trusted-types-2.0.7.tgz", - "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", - "optional": true - }, "@types/webpack-bundle-analyzer": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/@types/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.7.0.tgz", @@ -14584,14 +14561,6 @@ "domelementtype": "^2.2.0" } }, - "dompurify": { - "version": "3.2.4", - "resolved": "https://registry.npmmirror.com/dompurify/-/dompurify-3.2.4.tgz", - "integrity": "sha512-ysFSFEDVduQpyhzAob/kkuJjf5zWkZD8/A9ywSp1byueyuCfHamrCBa14/Oc2iiB0e51B+NpxSl5gmzn+Ms/mg==", - "requires": { - "@types/trusted-types": "^2.0.7" - } - }, "domutils": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", diff --git a/package.json b/package.json index 5abd32f..8aa174a 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,6 @@ "@quasar/extras": "^1.14.0", "core-js": "^3.6.5", "croner": "^4.3.9", - "dompurify": "^3.2.4", "monaco-editor": "^0.33.0", "monaco-editor-webpack-plugin": "^7.0.1", "picture-compressor": "^1.1.0", diff --git a/plugin/lib/ai.js b/plugin/lib/ai.js index edb7d1d..0f5e693 100644 --- a/plugin/lib/ai.js +++ b/plugin/lib/ai.js @@ -1,3 +1,18 @@ +const DOMPurify = require("dompurify"); +const marked = require("marked"); + +window.aiResponseParser = (content) => { + const markedContent = marked.parse(content.trim()); + const processedContent = markedContent + .replace("

", "

") + .replace("

", "

") + .replace("\n\n", ""); + const purifiedContent = DOMPurify.sanitize(processedContent, { + ADD_TAGS: ["think"], + }); + return purifiedContent; +}; + // 支持的模型类型 const API_TYPES = { OPENAI: "openai", @@ -303,7 +318,7 @@ async function chat(content, apiConfig, options = {}) { if (processBar) { quickcommand.updateProcessBar( { - text: fullResponse, + text: window.aiResponseParser(fullResponse), }, processBar ); @@ -410,5 +425,4 @@ async function getModels(apiConfig) { }; } } - module.exports = { chat, getModels }; diff --git a/plugin/lib/dialog/style.css b/plugin/lib/dialog/style.css index 30ebdd6..46a8fd5 100644 --- a/plugin/lib/dialog/style.css +++ b/plugin/lib/dialog/style.css @@ -600,7 +600,6 @@ textarea:focus { .process-text { font-size: 13px; margin-bottom: 8px; - white-space: pre-wrap; overflow-y: auto; overflow-x: hidden; padding-right: 2px; @@ -748,3 +747,86 @@ textarea:focus { .show-pause .process-pause-btn { display: flex; } + +/* markdown */ +#process p { + margin: 0; + line-height: 1.5; +} + +#process pre { + background-color: rgba(255, 255, 255, 0.1); + padding: 8px 10px; + border-radius: 4px; + margin: 4px 0; + overflow-x: auto; + max-width: 100%; + font-size: 12px; +} + +#process code { + font-family: Monaco, Consolas, Liberation Mono, monospace; + padding: 2px 4px; + background-color: rgba(255, 255, 255, 0.1); + border-radius: 3px; + font-size: 12px; +} + +#process pre code { + padding: 0; + background-color: transparent; +} + +#process ul, +#process ol { + margin: 4px 0; + padding-left: 1.2em; +} + +#process h1, +#process h2, +#process h3, +#process h4, +#process h5, +#process h6 { + margin: 6px 0 4px 0; + font-weight: 600; + line-height: 1.3; +} + +#process h1 { + font-size: 16px; +} + +#process h2 { + font-size: 15px; +} + +#process h3 { + font-size: 14px; +} + +#process h4, +#process h5, +#process h6 { + font-size: 13px; +} + +#process pre::-webkit-scrollbar { + height: 3px; +} + +#process think, +#process blockquote { + display: block; + color: rgba(255, 255, 255, 0.7); + border-left: 3px solid rgba(255, 255, 255, 0.3); + padding: 2px 0 2px 8px; + font-size: 12px; + margin: 4px 0; +} + +#process hr { + border-style: solid; + border-width: 0.5px; +} diff --git a/plugin/package-lock.json b/plugin/package-lock.json index f47bf9f..96c7071 100644 --- a/plugin/package-lock.json +++ b/plugin/package-lock.json @@ -8,6 +8,7 @@ "axios": "^1.7.9", "chrome-remote-interface": "^0.33.2", "crypto-js": "^4.2.0", + "dompurify": "^3.2.4", "exif-reader": "^2.0.1", "iconv-lite": "^0.6.3", "marked": "^15.0.7", @@ -25,6 +26,13 @@ "integrity": "sha512-Xtxw9n33I4guo8q0sDyZiRuxlfaopM454AKiELgU7l3tqsylCut6IBZ0fPy4ltSHsBib7M3yF7OEMoIuLwzWVg==", "license": "Apache-2.0" }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmmirror.com/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "license": "MIT", + "optional": true + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -86,6 +94,15 @@ "node": ">=0.4.0" } }, + "node_modules/dompurify": { + "version": "3.2.4", + "resolved": "https://registry.npmmirror.com/dompurify/-/dompurify-3.2.4.tgz", + "integrity": "sha512-ysFSFEDVduQpyhzAob/kkuJjf5zWkZD8/A9ywSp1byueyuCfHamrCBa14/Oc2iiB0e51B+NpxSl5gmzn+Ms/mg==", + "license": "(MPL-2.0 OR Apache-2.0)", + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } + }, "node_modules/exif-reader": { "version": "2.0.1", "resolved": "https://registry.npmmirror.com/exif-reader/-/exif-reader-2.0.1.tgz", @@ -264,6 +281,12 @@ "resolved": "https://registry.npmjs.org/@endo/env-options/-/env-options-1.1.8.tgz", "integrity": "sha512-Xtxw9n33I4guo8q0sDyZiRuxlfaopM454AKiELgU7l3tqsylCut6IBZ0fPy4ltSHsBib7M3yF7OEMoIuLwzWVg==" }, + "@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmmirror.com/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "optional": true + }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -311,6 +334,14 @@ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" }, + "dompurify": { + "version": "3.2.4", + "resolved": "https://registry.npmmirror.com/dompurify/-/dompurify-3.2.4.tgz", + "integrity": "sha512-ysFSFEDVduQpyhzAob/kkuJjf5zWkZD8/A9ywSp1byueyuCfHamrCBa14/Oc2iiB0e51B+NpxSl5gmzn+Ms/mg==", + "requires": { + "@types/trusted-types": "^2.0.7" + } + }, "exif-reader": { "version": "2.0.1", "resolved": "https://registry.npmmirror.com/exif-reader/-/exif-reader-2.0.1.tgz", diff --git a/plugin/package.json b/plugin/package.json index ef0946b..a9be277 100644 --- a/plugin/package.json +++ b/plugin/package.json @@ -3,6 +3,7 @@ "axios": "^1.7.9", "chrome-remote-interface": "^0.33.2", "crypto-js": "^4.2.0", + "dompurify": "^3.2.4", "exif-reader": "^2.0.1", "iconv-lite": "^0.6.3", "marked": "^15.0.7", diff --git a/plugin/preload.js b/plugin/preload.js index d5ce128..d99ca42 100644 --- a/plugin/preload.js +++ b/plugin/preload.js @@ -11,6 +11,7 @@ const http = require("http"); const https = require("https"); const url = require("url"); const crypto = require("crypto"); +const DOMPurify = require("dompurify"); require("ses"); const md5 = (input) => { @@ -19,6 +20,7 @@ const md5 = (input) => { window.lodashM = require("./lib/lodashMini"); window.pinyinMatch = require("pinyin-match"); +window.DOMPurify = DOMPurify; const createTerminalCommand = require("./lib/createTerminalCommand"); const shortCodes = require("./lib/shortCodes"); diff --git a/src/components/ai/AIChatHistory.vue b/src/components/ai/AIChatHistory.vue index e966587..78937fd 100644 --- a/src/components/ai/AIChatHistory.vue +++ b/src/components/ai/AIChatHistory.vue @@ -41,7 +41,6 @@