bug: md container 卡顿处理

This commit is contained in:
huangzhe
2025-08-04 17:40:17 +08:00
parent e390edf77e
commit c55c46bfab
4 changed files with 55 additions and 45 deletions

View File

@@ -208,11 +208,8 @@ export default {
axiosGetAiChat() {
const abortController = new AbortController()
this.requestSingle = abortController
this.messageInfo.information = this.genMessage.information || this.newMessage
// 重置 answerMap
this.messageInfo.information = (this.genMessage && this.genMessage.information) || this.newMessage
this.answerMap = ''
// this.typingQueue = []
this.currentMessage = JSON.parse(JSON.stringify(this.messageInfo))
const params = {
appType: "gwcsHelper2",
@@ -232,11 +229,12 @@ export default {
isDisLike: false,
}
if (this.genMessage) {
this.$set(this.messages, this.messages.length - 1, this.genMessage = { ...this.currentMessage })
// this.$set(this.messages, this.messages.length - 1, this.genMessage = { ...this.currentMessage })
this.messages.push({ ...this.currentMessage })
} else {
this.messages.push(this.currentMessage)
}
// 如果有自定义参数
// 自定义参数
if (this.chatData) {
for (let k in this.chatData) {
params[k] = this.chatData[k]
@@ -291,8 +289,6 @@ export default {
this.$emit('update:conversationId', data.conversation_id)
if (data.answer) {
this.answerMap += data.answer
let completeInformation = {}
let textContent = ''
@@ -309,7 +305,7 @@ export default {
textContent = text[1].trim()
}
console.log(`completeInformation: ${JSON.stringify(completeInformation)}, textContent: ${textContent}`);
// console.log(`completeInformation: ${JSON.stringify(completeInformation)}, textContent: ${textContent}`);
} catch (e) {
console.log(e);
@@ -318,10 +314,12 @@ export default {
if (!completeInformation && !textContent) {
return null
}
console.log(`textContent: ${textContent}`);
this.answerMap += textContent
const { information, is_complete } = completeInformation
this.messageInfo.information = information ? information : this.newMessage
this.messageInfo.information = information
this.messageInfo.is_complete = is_complete && is_complete.toString()
if (is_complete) {
@@ -329,9 +327,8 @@ export default {
this.requestIndex++
return null
}
return this.updateConversationState(data)
}
return this.updateConversationState(data)
} catch (error) {
console.error('流数据解析失败:', error)
return null
@@ -360,7 +357,7 @@ export default {
},
updateMessageContent(parse, requestIndex) {
let { event, answer, isThink, message_id } = parse
this.currentMessageID = message_id
// this.currentMessageID = message_id
if (!this.currentMessage || !answer) return
if (event !== 'message') return
@@ -387,20 +384,23 @@ export default {
// 取出一个完整文本块
const chunk = this.typingQueue.shift()
const chars = Array.from(chunk.answer)
const isThink = chunk.isThink
// const isThink = chunk.isThink
// 内部递归函数,用于逐字输出当前块
const outputChar = () => {
if (chars.length === 0) {
// 当前块输出完毕,继续处理下一个
setTimeout(typeNextChar, 10)
setTimeout(typeNextChar, 100)
return
}
const char = chars.shift() || ''
// console.log(`char`, char);
if (requestIndex === 2) {
this.$set(this.genMessage, 'text', this.genMessage.text + char)
// this.$forceUpdate()
} if (requestIndex === 1) {
this.$set(this.currentMessage, 'text', this.currentMessage.text + char)
// this.$forceUpdate()
}
const delay = this.getTypingDelay(char)
setTimeout(outputChar, delay)

View File

@@ -3,9 +3,6 @@ import Vue from "vue";
import KnowledgeCard from "../card/index.vue"
export function markdownContainer(markdownIt) {
// console.log(markdownIt);
// console.log(container);
container(markdownIt, "card", {
validate: function (params) {
// console.log(params.trim(), "title line");
@@ -14,9 +11,12 @@ export function markdownContainer(markdownIt) {
},
render: function (tokens, idx) {
// console.log(`tokens, idx`, tokens, idx);
return tokens[idx].content
// return tokens[idx].content
// return "<br/>--------<br/>"
},
content: function (tokens, idx, options, env, self) {
console.log(tokens[idx]);
// console.log(`args`, tokens, idx, options, env, self);
@@ -25,22 +25,24 @@ export function markdownContainer(markdownIt) {
// const { markup } = tokens[idx]
// console.log(`markup`, markup);
setTimeout(() => {
const dom = document.getElementById("cardTest");
// if (dom) return
// const vm = new Vue({
// el: "#cardTest",
// render: h => h(KnowledgeCard, {
// props: {
// content: tokens[idx]
// }
// })
// })
// console.log(`vue instance`, vm);
})
// setTimeout(() => {
// const dom = document.getElementById("cardTest");
// if (dom) return
// const vm = new Vue({
// el: "#cardTest",
// render: h => h(KnowledgeCard, {
// props: {
// content: tokens[idx]
// }
// })
// })
// console.log(`vue instance`, vm);
// })
// return tokens[idx]
// return "<div id='cardTest'></div>"
// console.log(tokens[idx].markup);
return tokens[idx].markup
}
})

View File

@@ -4,7 +4,7 @@ import { markdownContainer } from './markdown-it-container'
export const md = new MarkdownIt({
html: true,
breaks: true,
linkify: true,
typographer: true
}).use(markdownItKatex).use(markdownContainer)
}).use(markdownItKatex).use(markdownContainer)

View File

@@ -48,7 +48,10 @@
// icon
import { Icon } from 'vant'
import TreasureBox from '@/views/AI/components/treasureBox.vue'
import { md } from './js/markdown-it'
// import { md } from './js/markdown-it'
import MarkdownIt from 'markdown-it'
import markdownItKatex from 'markdown-it-katex'
import { markdownContainer } from './js/markdown-it-container'
export default {
@@ -70,16 +73,21 @@ export default {
},
data() {
return {
md,
primaryColor: '#57a6fc'
}
},
methods: {
render(message) {
const text = this.filterVisible(message)
// console.log(`text`, text);
return md.render(text)
const md = new MarkdownIt({
html: true,
breaks: true,
linkify: true,
typographer: true
}).use(markdownItKatex).use(markdownContainer)
return md.render(message.text)
},
setProductName(e) {
this.$emit('setProductName', e)
@@ -89,15 +97,15 @@ export default {
// 如果开头是中文,直接返回
// if (new RegExp('^[\u4e00-\u9fa5]+', 'g').test(text)) return text
text = text.replace(/<information>([^<]*)(?:<\/information>)?/g, '').trim()
text = text.replace(/<is_complete>([^<]*)(?:<\/is_complete>)?/g, '').trim()
// text = text.replace(/<information>([^<]*)(?:<\/information>)?/g, '').trim()
// text = text.replace(/<is_complete>([^<]*)(?:<\/is_complete>)?/g, '').trim()
// 捕获 不包含 < 的后置标签 span> /span> a</span>
text = text.replace(/^[/]?[a-zA-z0-9]+[</\w>]+/g, '').trim()
// text = text.replace(/^[/]?[a-zA-z0-9]+[</\w>]+/g, '').trim()
// // 尝试匹配 </abc> 标签
// text = text.replace(/^<\w+>/g, '').trim()
// text = text.replace(/^\w+/, "").trim()
text = text.replace(/<\/?([\w\s='"]+)?(?!>)$/gi, '').trim()
// text = text.replace(/<\/?([\w\s='"]+)?(?!>)$/gi, '').trim()
// console.log(`text`, text[text.length - 1]);
return text