feat: 模型思维链展示

This commit is contained in:
2025-06-29 16:09:46 +08:00
parent 0f03841f44
commit 867454eb84
6 changed files with 140 additions and 23 deletions

View File

@@ -13,7 +13,7 @@ import markdown from "@/components/markdown.vue";
import { useAsrStore, useChatStore, useLayoutStore } from "@/stores";
const chatStore = useChatStore();
const { historyMessages, completing, modelList, modelInfo } =
const { historyMessages, completing, modelList, modelInfo, thinking } =
storeToRefs(chatStore);
const asrStore = useAsrStore();
const { isRecording } = storeToRefs(asrStore);
@@ -23,6 +23,38 @@ const { hiddenLeftSidebar, simpleMode } = storeToRefs(layoutStore);
const inputData = ref("");
const scrollbarRef = ref<HTMLElement | null>(null);
const options = ref<Array<SelectGroupOption | SelectOption>>([]);
// NCollapse 组件的折叠状态
const collapseActive = ref<string[]>(
historyMessages.value.map((_, idx) => String(idx))
);
const getName = (idx: number) => String(idx);
watch(
historyMessages,
(newVal, oldVal) => {
// 取所有name
const newNames = newVal.map((_, idx) => getName(idx));
const oldNames = oldVal ? oldVal.map((_, idx) => getName(idx)) : [];
// 找出新增的name
const addedNames = newNames.filter((name) => !oldNames.includes(name));
// 保留原有已展开项
const currentActive = collapseActive.value.filter((name) =>
newNames.includes(name)
);
// 新增的默认展开
collapseActive.value = [...currentActive, ...addedNames];
},
{ deep: true }
);
const handleItemHeaderClick = (name: string) => {
if (collapseActive.value.includes(name)) {
collapseActive.value = collapseActive.value.filter((n) => n !== name);
} else {
collapseActive.value.push(name);
}
};
// 处理选中模型的 ID
const selectedModelId = computed({
@@ -111,11 +143,13 @@ onMounted(() => {
<NDivider />
</div>
</div>
<!-- 默认消息 历史消息 -->
<div
v-for="(msg, idx) in historyMessages"
:key="idx"
class="flex items-start mb-4"
>
<!-- 头像 -->
<span
v-if="msg.role === 'user'"
class="rounded-lg overflow-hidden !w-16 !min-w-16 !h-16"
@@ -125,10 +159,12 @@ onMounted(() => {
<span v-else class="rounded-lg overflow-hidden">
<avatar :avatar="AIAvatar" />
</span>
<!-- 头像 名称 -->
<div class="text-base w-full max-w-full ml-2 flex flex-col items-start">
<span class="text-base font-bold">{{
msg.role === "user" ? "你:" : "助手:"
}}</span>
<!-- 使用信息 -->
<div
v-if="msg.role !== 'user'"
class="text-[12px] text-[#7A7A7A] mb-[2px]"
@@ -136,6 +172,23 @@ onMounted(() => {
Tokens: <span class="mr-1">{{ msg.usage?.total_tokens }}</span>
</div>
<div class="w-full max-w-full">
<NCollapse
v-if="msg.thinking?.trim()"
:expanded-names="collapseActive[idx]"
>
<NCollapseItem
:title="thinking && idx === historyMessages.length - 1 ? '思考中...' : '已深度思考'"
:name="getName(idx)"
@item-header-click="() => handleItemHeaderClick(getName(idx))"
>
<div
class="text-[#7A7A7A] mb-4 border-l-2 border-[#E5E5E5] ml-2 pl-2"
>
<markdown :content="msg.thinking || ''" />
</div>
</NCollapseItem>
</NCollapse>
<!-- 内容↓ 思维链↑ -->
<markdown :content="msg.content || ''" />
<NDivider />
</div>
@@ -184,7 +237,7 @@ onMounted(() => {
</template>
<template #trigger>
<NButton :disabled="isRecording || completing" type="warning">
<template v-if="!simpleMode">清除历史</template>
<template v-if="!simpleMode"> 清除历史 </template>
<TrashIcon
class="!w-4 !h-4"
:class="{