askAi进度条支持markdown

This commit is contained in:
fofolee 2025-03-15 14:12:58 +08:00
parent 2fce45e13b
commit 07babda68e
13 changed files with 146 additions and 52 deletions

31
package-lock.json generated
View File

@ -11,7 +11,6 @@
"@quasar/extras": "^1.14.0", "@quasar/extras": "^1.14.0",
"core-js": "^3.6.5", "core-js": "^3.6.5",
"croner": "^4.3.9", "croner": "^4.3.9",
"dompurify": "^3.2.4",
"monaco-editor": "^0.33.0", "monaco-editor": "^0.33.0",
"monaco-editor-webpack-plugin": "^7.0.1", "monaco-editor-webpack-plugin": "^7.0.1",
"picture-compressor": "^1.1.0", "picture-compressor": "^1.1.0",
@ -2487,13 +2486,6 @@
"@types/node": "*" "@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": { "node_modules/@types/webpack-bundle-analyzer": {
"version": "4.7.0", "version": "4.7.0",
"resolved": "https://registry.npmjs.org/@types/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.7.0.tgz", "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" "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": { "node_modules/domutils": {
"version": "2.8.0", "version": "2.8.0",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
@ -13066,12 +13049,6 @@
"@types/node": "*" "@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": { "@types/webpack-bundle-analyzer": {
"version": "4.7.0", "version": "4.7.0",
"resolved": "https://registry.npmjs.org/@types/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.7.0.tgz", "resolved": "https://registry.npmjs.org/@types/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.7.0.tgz",
@ -14584,14 +14561,6 @@
"domelementtype": "^2.2.0" "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": { "domutils": {
"version": "2.8.0", "version": "2.8.0",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",

View File

@ -14,7 +14,6 @@
"@quasar/extras": "^1.14.0", "@quasar/extras": "^1.14.0",
"core-js": "^3.6.5", "core-js": "^3.6.5",
"croner": "^4.3.9", "croner": "^4.3.9",
"dompurify": "^3.2.4",
"monaco-editor": "^0.33.0", "monaco-editor": "^0.33.0",
"monaco-editor-webpack-plugin": "^7.0.1", "monaco-editor-webpack-plugin": "^7.0.1",
"picture-compressor": "^1.1.0", "picture-compressor": "^1.1.0",

View File

@ -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("<p><think>", "<think><p>")
.replace("</think></p>", "</p></think>")
.replace("<think>\n\n</think>", "");
const purifiedContent = DOMPurify.sanitize(processedContent, {
ADD_TAGS: ["think"],
});
return purifiedContent;
};
// 支持的模型类型 // 支持的模型类型
const API_TYPES = { const API_TYPES = {
OPENAI: "openai", OPENAI: "openai",
@ -303,7 +318,7 @@ async function chat(content, apiConfig, options = {}) {
if (processBar) { if (processBar) {
quickcommand.updateProcessBar( quickcommand.updateProcessBar(
{ {
text: fullResponse, text: window.aiResponseParser(fullResponse),
}, },
processBar processBar
); );
@ -410,5 +425,4 @@ async function getModels(apiConfig) {
}; };
} }
} }
module.exports = { chat, getModels }; module.exports = { chat, getModels };

View File

@ -600,7 +600,6 @@ textarea:focus {
.process-text { .process-text {
font-size: 13px; font-size: 13px;
margin-bottom: 8px; margin-bottom: 8px;
white-space: pre-wrap;
overflow-y: auto; overflow-y: auto;
overflow-x: hidden; overflow-x: hidden;
padding-right: 2px; padding-right: 2px;
@ -748,3 +747,86 @@ textarea:focus {
.show-pause .process-pause-btn { .show-pause .process-pause-btn {
display: flex; 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;
}

View File

@ -8,6 +8,7 @@
"axios": "^1.7.9", "axios": "^1.7.9",
"chrome-remote-interface": "^0.33.2", "chrome-remote-interface": "^0.33.2",
"crypto-js": "^4.2.0", "crypto-js": "^4.2.0",
"dompurify": "^3.2.4",
"exif-reader": "^2.0.1", "exif-reader": "^2.0.1",
"iconv-lite": "^0.6.3", "iconv-lite": "^0.6.3",
"marked": "^15.0.7", "marked": "^15.0.7",
@ -25,6 +26,13 @@
"integrity": "sha512-Xtxw9n33I4guo8q0sDyZiRuxlfaopM454AKiELgU7l3tqsylCut6IBZ0fPy4ltSHsBib7M3yF7OEMoIuLwzWVg==", "integrity": "sha512-Xtxw9n33I4guo8q0sDyZiRuxlfaopM454AKiELgU7l3tqsylCut6IBZ0fPy4ltSHsBib7M3yF7OEMoIuLwzWVg==",
"license": "Apache-2.0" "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": { "node_modules/asynckit": {
"version": "0.4.0", "version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
@ -86,6 +94,15 @@
"node": ">=0.4.0" "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": { "node_modules/exif-reader": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmmirror.com/exif-reader/-/exif-reader-2.0.1.tgz", "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", "resolved": "https://registry.npmjs.org/@endo/env-options/-/env-options-1.1.8.tgz",
"integrity": "sha512-Xtxw9n33I4guo8q0sDyZiRuxlfaopM454AKiELgU7l3tqsylCut6IBZ0fPy4ltSHsBib7M3yF7OEMoIuLwzWVg==" "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": { "asynckit": {
"version": "0.4.0", "version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "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", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" "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": { "exif-reader": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmmirror.com/exif-reader/-/exif-reader-2.0.1.tgz", "resolved": "https://registry.npmmirror.com/exif-reader/-/exif-reader-2.0.1.tgz",

View File

@ -3,6 +3,7 @@
"axios": "^1.7.9", "axios": "^1.7.9",
"chrome-remote-interface": "^0.33.2", "chrome-remote-interface": "^0.33.2",
"crypto-js": "^4.2.0", "crypto-js": "^4.2.0",
"dompurify": "^3.2.4",
"exif-reader": "^2.0.1", "exif-reader": "^2.0.1",
"iconv-lite": "^0.6.3", "iconv-lite": "^0.6.3",
"marked": "^15.0.7", "marked": "^15.0.7",

View File

@ -11,6 +11,7 @@ const http = require("http");
const https = require("https"); const https = require("https");
const url = require("url"); const url = require("url");
const crypto = require("crypto"); const crypto = require("crypto");
const DOMPurify = require("dompurify");
require("ses"); require("ses");
const md5 = (input) => { const md5 = (input) => {
@ -19,6 +20,7 @@ const md5 = (input) => {
window.lodashM = require("./lib/lodashMini"); window.lodashM = require("./lib/lodashMini");
window.pinyinMatch = require("pinyin-match"); window.pinyinMatch = require("pinyin-match");
window.DOMPurify = DOMPurify;
const createTerminalCommand = require("./lib/createTerminalCommand"); const createTerminalCommand = require("./lib/createTerminalCommand");
const shortCodes = require("./lib/shortCodes"); const shortCodes = require("./lib/shortCodes");

View File

@ -41,7 +41,6 @@
<script> <script>
import { defineComponent } from "vue"; import { defineComponent } from "vue";
import DOMPurify from "dompurify";
export default defineComponent({ export default defineComponent({
name: "AIChatHistory", name: "AIChatHistory",
@ -82,15 +81,7 @@ export default defineComponent({
}, },
getAssistantMsg(content) { getAssistantMsg(content) {
const markedContent = quickcommand.markdownParse(content.trim()); return window.aiResponseParser(content);
const processedContent = markedContent
.replace("<p><think>", "<think><p>")
.replace("</think></p>", "</p></think>")
.replace("<think>\n\n</think>", "");
const purifiedContent = DOMPurify.sanitize(processedContent, {
ADD_TAGS: ["think"],
});
return purifiedContent;
}, },
getUserMsg(content) { getUserMsg(content) {

View File

@ -56,7 +56,6 @@
import CommandTypeTag from "../CommandTypeTag.vue"; import CommandTypeTag from "../CommandTypeTag.vue";
import platformTypes from "js/options/platformTypes.js"; import platformTypes from "js/options/platformTypes.js";
import programs from "js/options/programs.js"; import programs from "js/options/programs.js";
import DOMPurify from "dompurify";
export default { export default {
name: "DenseLayout", name: "DenseLayout",
@ -90,7 +89,7 @@ export default {
}, },
methods: { methods: {
purify(content) { purify(content) {
return DOMPurify.sanitize(content); return window.DOMPurify.sanitize(content);
}, },
}, },
}; };

View File

@ -51,7 +51,6 @@
import CommandTypeTag from "../CommandTypeTag.vue"; import CommandTypeTag from "../CommandTypeTag.vue";
import platformTypes from "js/options/platformTypes.js"; import platformTypes from "js/options/platformTypes.js";
import programs from "js/options/programs.js"; import programs from "js/options/programs.js";
import DOMPurify from "dompurify";
export default { export default {
name: "ListLayout", name: "ListLayout",
@ -82,7 +81,7 @@ export default {
}, },
methods: { methods: {
purify(content) { purify(content) {
return DOMPurify.sanitize(content); return window.DOMPurify.sanitize(content);
}, },
}, },
}; };

View File

@ -35,7 +35,6 @@
<script> <script>
import CommandTypeTag from "../CommandTypeTag.vue"; import CommandTypeTag from "../CommandTypeTag.vue";
import platformTypes from "js/options/platformTypes.js"; import platformTypes from "js/options/platformTypes.js";
import DOMPurify from "dompurify";
export default { export default {
name: "MiniLayout", name: "MiniLayout",
@ -52,7 +51,7 @@ export default {
}, },
methods: { methods: {
purify(content) { purify(content) {
return DOMPurify.sanitize(content); return window.DOMPurify.sanitize(content);
}, },
}, },
}; };

View File

@ -11,7 +11,7 @@
</q-card-section> </q-card-section>
<q-card-section <q-card-section
v-if="options.isHtml" v-if="options.isHtml"
v-html="options.message" v-html="purify(options.message)"
class="content" class="content"
/> />
<q-card-section v-else v-text="options.message" class="content" /> <q-card-section v-else v-text="options.message" class="content" />
@ -32,6 +32,9 @@ export default {
this.$emit("clickOK", true); this.$emit("clickOK", true);
this.hide(); this.hide();
}, },
purify(html) {
return window.DOMPurify.sanitize(html);
},
}, },
props: { props: {
options: Object, options: Object,

View File

@ -85,3 +85,8 @@
color: #007bff; color: #007bff;
text-decoration: none; text-decoration: none;
} }
.markdown hr {
border-style: solid;
border-width: 0.5px;
}