fix: 修复终止输出,修复思考模型<think>标签的兼容处理
This commit is contained in:
parent
b2574805fd
commit
63e4ce739b
@ -111,6 +111,7 @@ function handleClick(item: GetSessionListVO) {
|
||||
.model-select-box {
|
||||
color: var(--el-color-primary, #409eff);
|
||||
border: 1px solid var(--el-color-primary, #409eff);
|
||||
background: var(--el-color-primary-light-9, rgb(235.9, 245.3, 255));
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
|
||||
@ -1,79 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import type { ConversationItem } from 'vue-element-plus-x/types/Conversations';
|
||||
import type { ChatSessionVo } from '@/api/session/types';
|
||||
// import { useUserStore } from '@/stores';
|
||||
import { Conversations } from 'vue-element-plus-x';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
// import { get_session_list } from '@/api';
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
// const userStore = useUserStore();
|
||||
const active = computed<string>(() => (route.params?.id as string) ?? '');
|
||||
const items = ref<ConversationItem<ChatSessionVo>[]>([]);
|
||||
|
||||
function handleChange(item: ConversationItem<ChatSessionVo>) {
|
||||
console.log(item);
|
||||
// router.replace({
|
||||
// name: 'chat',
|
||||
// params: {
|
||||
// id: item.id,
|
||||
// },
|
||||
// });
|
||||
}
|
||||
|
||||
// async function getSessions() {
|
||||
// try {
|
||||
// const res = await get_session_list({
|
||||
// userId: userStore.userInfo?.userId as number,
|
||||
// });
|
||||
// console.log(res);
|
||||
// items.value
|
||||
// = res.rows?.map(item => ({
|
||||
// ...item,
|
||||
// label: item.sessionTitle as string,
|
||||
// })) ?? [];
|
||||
// }
|
||||
// catch (error) {
|
||||
// console.error('getSessions:', error);
|
||||
// }
|
||||
// }
|
||||
// getSessions();
|
||||
|
||||
const sessionId = computed<string>(() => route.params?.id as string);
|
||||
function handleNewSession() {
|
||||
if (sessionId.value) {
|
||||
router.replace({ name: 'chatWithId' });
|
||||
}
|
||||
}
|
||||
|
||||
// watchEffect(() => {
|
||||
// console.log('active', active.value, '>>>');
|
||||
// });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-container class="h-screen overflow-hidden">
|
||||
<el-aside>
|
||||
<Conversations
|
||||
:active="active"
|
||||
:items="items"
|
||||
row-key="id"
|
||||
label-key="sessionTitle"
|
||||
@change="handleChange"
|
||||
>
|
||||
<template #header>
|
||||
<el-button @click="handleNewSession">
|
||||
新增
|
||||
</el-button>
|
||||
</template>
|
||||
<template #footer>
|
||||
<div>用户信息</div>
|
||||
</template>
|
||||
</Conversations>
|
||||
</el-aside>
|
||||
<el-main>
|
||||
<RouterView />
|
||||
</el-main>
|
||||
</el-container>
|
||||
</template>
|
||||
@ -43,6 +43,8 @@ const bubbleListRef = ref<BubbleListInstance | null>(null);
|
||||
const isLoading = ref(false);
|
||||
// 记录发送的返回
|
||||
let sendRequest: HookFetchRequest<any, any> | null = null;
|
||||
// 记录进入思考中
|
||||
let isThinking = false;
|
||||
|
||||
watch(
|
||||
() => route.params?.id,
|
||||
@ -95,23 +97,47 @@ function handleDataChunk(chunk: AnyObject) {
|
||||
// 开始思考链状态
|
||||
bubbleItems.value[bubbleItems.value.length - 1].thinkingStatus = 'thinking';
|
||||
bubbleItems.value[bubbleItems.value.length - 1].loading = true;
|
||||
bubbleItems.value[bubbleItems.value.length - 1].thinlCollapse = true;
|
||||
if (bubbleItems.value.length) {
|
||||
bubbleItems.value[bubbleItems.value.length - 1].reasoning_content += reasoningChunk;
|
||||
}
|
||||
}
|
||||
|
||||
// 另一种思考中形式,content中有 <think></think> 的格式
|
||||
// 一开始匹配到 <think> 开始,匹配到 </think> 结束,并处理标签中的内容为思考内容
|
||||
const parsedChunk = chunk.choices?.[0].delta.content;
|
||||
if (parsedChunk) {
|
||||
const thinkStart = parsedChunk.includes('<think>');
|
||||
const thinkEnd = parsedChunk.includes('</think>');
|
||||
if (thinkStart) {
|
||||
isThinking = true;
|
||||
}
|
||||
if (thinkEnd) {
|
||||
isThinking = false;
|
||||
}
|
||||
if (isThinking) {
|
||||
// 开始思考链状态
|
||||
bubbleItems.value[bubbleItems.value.length - 1].thinkingStatus = 'thinking';
|
||||
bubbleItems.value[bubbleItems.value.length - 1].loading = true;
|
||||
bubbleItems.value[bubbleItems.value.length - 1].thinlCollapse = true;
|
||||
if (bubbleItems.value.length) {
|
||||
bubbleItems.value[bubbleItems.value.length - 1].reasoning_content += parsedChunk
|
||||
.replace('<think>', '')
|
||||
.replace('</think>', '');
|
||||
}
|
||||
}
|
||||
else {
|
||||
// 结束 思考链状态
|
||||
bubbleItems.value[bubbleItems.value.length - 1].thinkingStatus = 'end';
|
||||
bubbleItems.value[bubbleItems.value.length - 1].loading = false;
|
||||
|
||||
if (bubbleItems.value.length) {
|
||||
bubbleItems.value[bubbleItems.value.length - 1].content += parsedChunk;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
// 这里如果使用了中断,会有报错,可以忽略不管
|
||||
console.error('解析数据时出错:', err);
|
||||
}
|
||||
}
|
||||
@ -189,6 +215,7 @@ function addMessage(message: string, isUser: boolean) {
|
||||
content: message || '',
|
||||
reasoning_content: '',
|
||||
thinkingStatus: 'start',
|
||||
thinlCollapse: false,
|
||||
};
|
||||
bubbleItems.value.push(obj);
|
||||
}
|
||||
@ -226,6 +253,7 @@ watch(
|
||||
<template #header="{ item }">
|
||||
<Thinking
|
||||
v-if="item.reasoning_content"
|
||||
v-model="item.thinlCollapse"
|
||||
:content="item.reasoning_content"
|
||||
:status="item.thinkingStatus"
|
||||
class="thinking-chain-warp"
|
||||
|
||||
@ -25,6 +25,7 @@ export const useChatStore = defineStore('chat', () => {
|
||||
const setChatMap = (id: string, data: ChatMessageVo[]) => {
|
||||
chatMap.value[id] = data?.map((item: ChatMessageVo) => {
|
||||
const isUser = item.role === 'user';
|
||||
const thinkContent = extractThkContent(item.content as string);
|
||||
return {
|
||||
...item,
|
||||
key: item.id,
|
||||
@ -37,6 +38,10 @@ export const useChatStore = defineStore('chat', () => {
|
||||
: 'https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png',
|
||||
avatarSize: '32px',
|
||||
typing: false,
|
||||
reasoning_content: thinkContent,
|
||||
thinkingStatus: 'end',
|
||||
content: extractThkContentAfter(item.content as string),
|
||||
thinlCollapse: false,
|
||||
};
|
||||
});
|
||||
};
|
||||
@ -60,6 +65,27 @@ export const useChatStore = defineStore('chat', () => {
|
||||
}
|
||||
};
|
||||
|
||||
// 对思考中的内容回显做处理
|
||||
function extractThkContent(content: string) {
|
||||
const regex = /<think>(.*?)<\/think>/s;
|
||||
const matchResult = content.match(regex);
|
||||
// 把这些内容从 content 中移除
|
||||
content = content.replace(regex, '');
|
||||
return matchResult?.[1] ?? '';
|
||||
}
|
||||
|
||||
// 如果有 </think> 标签,则把 </think> 之后的 内容从 content 中返回
|
||||
function extractThkContentAfter(content: string) {
|
||||
if (!content.includes('</think>')) {
|
||||
return content;
|
||||
}
|
||||
const regex = /<\/think>(.*)/s;
|
||||
const matchResult = content.match(regex);
|
||||
// 把这些内容从 content 中移除
|
||||
content = content.replace(regex, '');
|
||||
return matchResult?.[1] ?? '';
|
||||
}
|
||||
|
||||
return {
|
||||
chatMap,
|
||||
requestChatList,
|
||||
|
||||
@ -28,23 +28,23 @@
|
||||
height: fit-content;
|
||||
}
|
||||
|
||||
.zoom-fade-enter-from {
|
||||
.rounded-tooltip-enter-from {
|
||||
transform: scale(0.9); /* 进入前:缩小隐藏 */
|
||||
opacity: 0;
|
||||
}
|
||||
.zoom-fade-enter-active,
|
||||
.zoom-fade-leave-active {
|
||||
.rounded-tooltip-enter-active,
|
||||
.rounded-tooltip-leave-active {
|
||||
transition: transform 0.3s, opacity 0.3s; /* 缓入动画 */
|
||||
}
|
||||
.zoom-fade-enter-to {
|
||||
.rounded-tooltip-enter-to {
|
||||
transform: scale(1); /* 进入后:正常大小 */
|
||||
opacity: 1;
|
||||
}
|
||||
.zoom-fade-leave-from {
|
||||
.rounded-tooltip-leave-from {
|
||||
transform: scale(1); /* 离开前:正常大小 */
|
||||
opacity: 1;
|
||||
}
|
||||
.zoom-fade-leave-to {
|
||||
.rounded-tooltip-leave-to {
|
||||
transform: scale(0.9); /* 离开后:缩小隐藏 */
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user