import type { ChatMessageVo } from '@/api/chat/types'; import { defineStore } from 'pinia'; import { getChatList } from '@/api'; import { getUserProfilePicture, systemProfilePicture } from '@/utils/user.ts'; import { useUserStore } from './user'; export const useChatStore = defineStore('chat', () => { const userStore = useUserStore(); // 是否开启深度思考 const isDeepThinking = ref(false); const setDeepThinking = (value: boolean) => { isDeepThinking.value = value; }; // 会议ID对应-聊天记录 map对象 const chatMap = ref>({}); /** * 解析消息内容,提取文本、图片和文件信息 * @param content - 消息内容,可能是字符串或数组格式的JSON字符串 * @returns 解析后的文本内容、图片列表和文件列表 */ function parseMessageContent(content: string | any): { text: string; images: Array<{ url: string; name?: string }>; files: Array<{ name: string; size: number }>; } { let text = ''; const images: Array<{ url: string; name?: string }> = []; const files: Array<{ name: string; size: number }> = []; try { // 如果 content 是字符串,尝试解析为 JSON let contentArray: any; if (typeof content === 'string') { // 尝试解析 JSON 数组格式 if (content.trim().startsWith('[')) { contentArray = JSON.parse(content); } else { // 普通文本 text = content; return { text, images, files }; } } else { contentArray = content; } // 如果不是数组,直接返回 if (!Array.isArray(contentArray)) { text = String(content); return { text, images, files }; } // 遍历数组,提取文本和图片 for (const item of contentArray) { if (item.type === 'text') { text += item.text || ''; } else if (item.type === 'image_url') { if (item.image_url?.url) { images.push({ url: item.image_url.url, name: item.image_url.name, }); } } } // 从文本中提取文件信息(如果有 ATTACHMENT_FILE 标签) const fileMatches = text.matchAll(/[\s\S]*?(.*?)<\/FILE_NAME>[\s\S]*?<\/ATTACHMENT_FILE>/g); for (const match of fileMatches) { const fileName = match[1]; files.push({ name: fileName, size: 0, // 从历史记录中无法获取文件大小 }); } // 从文本中移除 ATTACHMENT_FILE 标签及其内容,只保留文件卡片显示 text = text.replace(/[\s\S]*?<\/ATTACHMENT_FILE>/g, '').trim(); return { text, images, files }; } catch (error) { console.error('解析消息内容失败:', error); // 解析失败,返回原始内容 return { text: String(content), images: [], files: [], }; } } const setChatMap = (id: string, data: ChatMessageVo[]) => { chatMap.value[id] = data?.map((item: ChatMessageVo) => { const isUser = item.role === 'user'; // 解析消息内容 const { text, images, files } = parseMessageContent(item.content as string); // 处理思考内容 const thinkContent = extractThkContent(text); const finalContent = extractThkContentAfter(text); return { ...item, key: item.id, placement: isUser ? 'end' : 'start', isMarkdown: !isUser, avatar: isUser ? getUserProfilePicture() : systemProfilePicture, avatarSize: '32px', typing: false, reasoning_content: thinkContent, thinkingStatus: 'end', content: finalContent, thinlCollapse: false, // 保留图片和文件信息(优先使用解析出来的,如果没有则使用原有的) images: images.length > 0 ? images : item.images, files: files.length > 0 ? files : item.files, }; }); }; // 获取当前会话的聊天记录 const requestChatList = async (sessionId: string) => { // 如果没有 token 则不查询聊天记录 if (!userStore.token) return; try { const res = await getChatList({ sessionId, userId: userStore.userInfo?.userId as number, }); if (res.data.items) { setChatMap(sessionId, res.data.items); } } catch (error) { console.error('getChatList:', error); } }; // 对思考中的内容回显做处理 function extractThkContent(content: string) { const regex = /(.*?)<\/think>/s; const matchResult = content.match(regex); // 把这些内容从 content 中移除 content = content.replace(regex, ''); return matchResult?.[1] ?? ''; } // 如果有 标签,则把 之后的 内容从 content 中返回 function extractThkContentAfter(content: string) { if (!content.includes('')) { return content; } const regex = /<\/think>(.*)/s; const matchResult = content.match(regex); // 把这些内容从 content 中移除 content = content.replace(regex, ''); return matchResult?.[1] ?? ''; } return { chatMap, requestChatList, isDeepThinking, setDeepThinking, }; });