Files
QuestionProject/ai_knowledge_base_v2/apps/admin-web/src/components/StreamingMarkdownMessage.vue

54 lines
1.7 KiB
Vue

<script setup lang="ts">
import MarkdownIt from "markdown-it";
import { computed } from "vue";
const props = defineProps<{
content: string;
streaming?: boolean;
}>();
const markdown = new MarkdownIt({ breaks: true, html: false, linkify: true });
const answer = computed(() => stripStreamingReasoning(props.content).replace(/^\s+/, ""));
const renderedContent = computed(() => answer.value.trim() ? markdown.render(answer.value) : "");
function stripStreamingReasoning(content: string) {
const lower = content.toLowerCase();
let visible = "";
let cursor = 0;
let reasoningDepth = 0;
while (cursor < content.length) {
const tagStart = content.indexOf("<", cursor);
if (tagStart === -1) {
if (reasoningDepth === 0) visible += content.slice(cursor);
break;
}
if (reasoningDepth === 0) visible += content.slice(cursor, tagStart);
const tail = lower.slice(tagStart);
const openTag = tail.match(/^<think(?:\s[^>]*)?>/);
if (openTag) {
reasoningDepth += 1;
cursor = tagStart + openTag[0].length;
continue;
}
const closeTag = tail.match(/^<\/think\s*>/);
if (closeTag) {
reasoningDepth = Math.max(0, reasoningDepth - 1);
cursor = tagStart + closeTag[0].length;
continue;
}
if ("<think".startsWith(tail) || "</think>".startsWith(tail)) break;
if (reasoningDepth === 0) visible += "<";
cursor = tagStart + 1;
}
return visible;
}
</script>
<template>
<div v-if="renderedContent" class="agent-preview-markdown" v-html="renderedContent"></div>
<div v-else-if="streaming" class="agent-preview-generation-state">
<span></span><span></span><span></span>
思考中
</div>
</template>