fix: 文件上传优化
This commit is contained in:
15
Yi.Ai.Vue3/pnpm-lock.yaml
generated
15
Yi.Ai.Vue3/pnpm-lock.yaml
generated
@@ -3467,6 +3467,9 @@ packages:
|
|||||||
mlly@1.7.4:
|
mlly@1.7.4:
|
||||||
resolution: {integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==}
|
resolution: {integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==}
|
||||||
|
|
||||||
|
mlly@1.8.0:
|
||||||
|
resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==}
|
||||||
|
|
||||||
mri@1.2.0:
|
mri@1.2.0:
|
||||||
resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
|
resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
@@ -5770,7 +5773,7 @@ snapshots:
|
|||||||
jiti: 2.4.2
|
jiti: 2.4.2
|
||||||
klona: 2.0.6
|
klona: 2.0.6
|
||||||
knitwork: 1.2.0
|
knitwork: 1.2.0
|
||||||
mlly: 1.7.4
|
mlly: 1.8.0
|
||||||
ohash: 2.0.11
|
ohash: 2.0.11
|
||||||
pathe: 2.0.3
|
pathe: 2.0.3
|
||||||
pkg-types: 2.1.0
|
pkg-types: 2.1.0
|
||||||
@@ -8943,6 +8946,14 @@ snapshots:
|
|||||||
pkg-types: 1.3.1
|
pkg-types: 1.3.1
|
||||||
ufo: 1.6.1
|
ufo: 1.6.1
|
||||||
|
|
||||||
|
mlly@1.8.0:
|
||||||
|
dependencies:
|
||||||
|
acorn: 8.15.0
|
||||||
|
pathe: 2.0.3
|
||||||
|
pkg-types: 1.3.1
|
||||||
|
ufo: 1.6.1
|
||||||
|
optional: true
|
||||||
|
|
||||||
mri@1.2.0: {}
|
mri@1.2.0: {}
|
||||||
|
|
||||||
mrmime@2.0.1: {}
|
mrmime@2.0.1: {}
|
||||||
@@ -10330,7 +10341,7 @@ snapshots:
|
|||||||
estree-walker: 3.0.3
|
estree-walker: 3.0.3
|
||||||
local-pkg: 1.1.1
|
local-pkg: 1.1.1
|
||||||
magic-string: 0.30.17
|
magic-string: 0.30.17
|
||||||
mlly: 1.7.4
|
mlly: 1.8.0
|
||||||
pathe: 2.0.3
|
pathe: 2.0.3
|
||||||
picomatch: 4.0.3
|
picomatch: 4.0.3
|
||||||
pkg-types: 2.1.0
|
pkg-types: 2.1.0
|
||||||
|
|||||||
@@ -413,24 +413,49 @@ onChange(async (files) => {
|
|||||||
// 处理图片文件
|
// 处理图片文件
|
||||||
if (isImage) {
|
if (isImage) {
|
||||||
try {
|
try {
|
||||||
// 先压缩图片
|
// 多级压缩策略:逐步降低质量和分辨率
|
||||||
const compressedBlob = await compressImage(file, 1024, 1024, 0.8);
|
const compressionLevels = [
|
||||||
// 再转换为 base64
|
{ maxWidth: 800, maxHeight: 800, quality: 0.6 },
|
||||||
const base64 = await blobToBase64(compressedBlob);
|
{ maxWidth: 600, maxHeight: 600, quality: 0.5 },
|
||||||
|
{ maxWidth: 400, maxHeight: 400, quality: 0.4 },
|
||||||
|
];
|
||||||
|
|
||||||
// 检查总长度(base64 保守估计占用)
|
let compressedBlob: Blob | null = null;
|
||||||
const estimatedLength = Math.floor(base64.length * 0.5);
|
let base64 = '';
|
||||||
if (totalContentLength + estimatedLength > MAX_TOTAL_CONTENT_LENGTH) {
|
let compressionLevel = 0;
|
||||||
ElMessage.error(`添加 ${file.name} 会超过消息总长度限制(${MAX_TOTAL_CONTENT_LENGTH} 字符),已跳过`);
|
|
||||||
continue;
|
// 尝试不同级别的压缩
|
||||||
|
for (const level of compressionLevels) {
|
||||||
|
compressionLevel++;
|
||||||
|
compressedBlob = await compressImage(file, level.maxWidth, level.maxHeight, level.quality);
|
||||||
|
base64 = await blobToBase64(compressedBlob);
|
||||||
|
|
||||||
|
// 检查是否满足总长度限制
|
||||||
|
const estimatedLength = Math.floor(base64.length * 0.5);
|
||||||
|
if (totalContentLength + estimatedLength <= MAX_TOTAL_CONTENT_LENGTH) {
|
||||||
|
// 满足限制,使用当前压缩级别
|
||||||
|
totalContentLength += estimatedLength;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果是最后一级压缩仍然超限,则跳过
|
||||||
|
if (compressionLevel === compressionLevels.length) {
|
||||||
|
const fileSizeMB = (file.size / 1024 / 1024).toFixed(2);
|
||||||
|
ElMessage.error(`${file.name} (${fileSizeMB}MB) 即使压缩后仍超过总内容限制,已跳过`);
|
||||||
|
compressedBlob = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
totalContentLength += estimatedLength;
|
// 如果压缩失败,跳过此文件
|
||||||
|
if (!compressedBlob) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// 计算压缩比例
|
// 计算压缩比例
|
||||||
const originalSize = (file.size / 1024).toFixed(2);
|
const originalSize = (file.size / 1024).toFixed(2);
|
||||||
const compressedSize = (compressedBlob.size / 1024).toFixed(2);
|
const compressedSize = (compressedBlob.size / 1024).toFixed(2);
|
||||||
console.log(`图片压缩: ${file.name} - 原始: ${originalSize}KB, 压缩后: ${compressedSize}KB`);
|
console.log(`图片压缩: ${file.name} - 原始: ${originalSize}KB, 压缩后: ${compressedSize}KB (级别${compressionLevel})`);
|
||||||
|
|
||||||
arr.push({
|
arr.push({
|
||||||
uid: crypto.randomUUID(),
|
uid: crypto.randomUUID(),
|
||||||
@@ -458,13 +483,23 @@ onChange(async (files) => {
|
|||||||
try {
|
try {
|
||||||
const result = await parseExcel(file);
|
const result = await parseExcel(file);
|
||||||
|
|
||||||
// 检查总长度
|
// 动态裁剪内容以适应剩余空间
|
||||||
if (totalContentLength + result.content.length > MAX_TOTAL_CONTENT_LENGTH) {
|
let finalContent = result.content;
|
||||||
ElMessage.error(`添加 ${file.name} 会超过消息总长度限制(${MAX_TOTAL_CONTENT_LENGTH} 字符),已跳过`);
|
let wasTruncated = result.totalRows > MAX_EXCEL_ROWS;
|
||||||
|
|
||||||
|
// 如果超过总内容限制,裁剪内容
|
||||||
|
const remainingSpace = MAX_TOTAL_CONTENT_LENGTH - totalContentLength;
|
||||||
|
if (result.content.length > remainingSpace && remainingSpace > 1000) {
|
||||||
|
// 至少保留1000字符才有意义
|
||||||
|
finalContent = result.content.substring(0, remainingSpace);
|
||||||
|
wasTruncated = true;
|
||||||
|
} else if (remainingSpace <= 1000) {
|
||||||
|
const fileSizeKB = (file.size / 1024).toFixed(2);
|
||||||
|
ElMessage.error(`${file.name} (${fileSizeKB}KB) 会超过总内容限制,已跳过`);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
totalContentLength += result.content.length;
|
totalContentLength += finalContent.length;
|
||||||
|
|
||||||
arr.push({
|
arr.push({
|
||||||
uid: crypto.randomUUID(),
|
uid: crypto.randomUUID(),
|
||||||
@@ -475,16 +510,17 @@ onChange(async (files) => {
|
|||||||
showDelIcon: true,
|
showDelIcon: true,
|
||||||
imgPreview: false,
|
imgPreview: false,
|
||||||
isUploaded: true,
|
isUploaded: true,
|
||||||
fileContent: result.content,
|
fileContent: finalContent,
|
||||||
fileType: 'text',
|
fileType: 'text',
|
||||||
});
|
});
|
||||||
|
|
||||||
// 提示信息
|
// 提示信息
|
||||||
if (result.totalRows > MAX_EXCEL_ROWS) {
|
if (wasTruncated) {
|
||||||
ElMessage.warning(`${file.name} 共 ${result.totalRows} 行,已提取前 ${result.extractedRows} 行`);
|
const fileSizeKB = (file.size / 1024).toFixed(2);
|
||||||
|
ElMessage.warning(`${file.name} (${fileSizeKB}KB) 内容过大,已自动截取部分内容`);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`Excel 解析: ${file.name} - 大小: ${(file.size / 1024).toFixed(2)}KB, 总行数: ${result.totalRows}, 已提取: ${result.extractedRows} 行, 内容长度: ${result.content.length} 字符`);
|
console.log(`Excel 解析: ${file.name} - 大小: ${(file.size / 1024).toFixed(2)}KB, 总行数: ${result.totalRows}, 已提取: ${result.extractedRows} 行, 内容长度: ${finalContent.length} 字符`);
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
console.error('解析 Excel 失败:', error);
|
console.error('解析 Excel 失败:', error);
|
||||||
@@ -497,13 +533,22 @@ onChange(async (files) => {
|
|||||||
try {
|
try {
|
||||||
const result = await parseWord(file);
|
const result = await parseWord(file);
|
||||||
|
|
||||||
// 检查总长度
|
// 动态裁剪内容以适应剩余空间
|
||||||
if (totalContentLength + result.content.length > MAX_TOTAL_CONTENT_LENGTH) {
|
let finalContent = result.content;
|
||||||
ElMessage.error(`添加 ${file.name} 会超过消息总长度限制(${MAX_TOTAL_CONTENT_LENGTH} 字符),已跳过`);
|
let wasTruncated = result.extracted;
|
||||||
|
|
||||||
|
// 如果超过总内容限制,裁剪内容
|
||||||
|
const remainingSpace = MAX_TOTAL_CONTENT_LENGTH - totalContentLength;
|
||||||
|
if (result.content.length > remainingSpace && remainingSpace > 1000) {
|
||||||
|
finalContent = result.content.substring(0, remainingSpace);
|
||||||
|
wasTruncated = true;
|
||||||
|
} else if (remainingSpace <= 1000) {
|
||||||
|
const fileSizeKB = (file.size / 1024).toFixed(2);
|
||||||
|
ElMessage.error(`${file.name} (${fileSizeKB}KB) 会超过总内容限制,已跳过`);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
totalContentLength += result.content.length;
|
totalContentLength += finalContent.length;
|
||||||
|
|
||||||
arr.push({
|
arr.push({
|
||||||
uid: crypto.randomUUID(),
|
uid: crypto.randomUUID(),
|
||||||
@@ -514,16 +559,17 @@ onChange(async (files) => {
|
|||||||
showDelIcon: true,
|
showDelIcon: true,
|
||||||
imgPreview: false,
|
imgPreview: false,
|
||||||
isUploaded: true,
|
isUploaded: true,
|
||||||
fileContent: result.content,
|
fileContent: finalContent,
|
||||||
fileType: 'text',
|
fileType: 'text',
|
||||||
});
|
});
|
||||||
|
|
||||||
// 提示信息
|
// 提示信息
|
||||||
if (result.extracted) {
|
if (wasTruncated) {
|
||||||
ElMessage.warning(`${file.name} 共 ${result.totalLength} 字符,已提取前 ${MAX_WORD_LENGTH} 字符`);
|
const fileSizeKB = (file.size / 1024).toFixed(2);
|
||||||
|
ElMessage.warning(`${file.name} (${fileSizeKB}KB) 内容过大,已自动截取部分内容`);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`Word 解析: ${file.name} - 大小: ${(file.size / 1024).toFixed(2)}KB, 总长度: ${result.totalLength}, 已提取: ${result.content.length} 字符`);
|
console.log(`Word 解析: ${file.name} - 大小: ${(file.size / 1024).toFixed(2)}KB, 总长度: ${result.totalLength}, 已提取: ${finalContent.length} 字符`);
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
console.error('解析 Word 失败:', error);
|
console.error('解析 Word 失败:', error);
|
||||||
@@ -536,13 +582,22 @@ onChange(async (files) => {
|
|||||||
try {
|
try {
|
||||||
const result = await parsePDF(file);
|
const result = await parsePDF(file);
|
||||||
|
|
||||||
// 检查总长度
|
// 动态裁剪内容以适应剩余空间
|
||||||
if (totalContentLength + result.content.length > MAX_TOTAL_CONTENT_LENGTH) {
|
let finalContent = result.content;
|
||||||
ElMessage.error(`添加 ${file.name} 会超过消息总长度限制(${MAX_TOTAL_CONTENT_LENGTH} 字符),已跳过`);
|
let wasTruncated = result.totalPages > MAX_PDF_PAGES;
|
||||||
|
|
||||||
|
// 如果超过总内容限制,裁剪内容
|
||||||
|
const remainingSpace = MAX_TOTAL_CONTENT_LENGTH - totalContentLength;
|
||||||
|
if (result.content.length > remainingSpace && remainingSpace > 1000) {
|
||||||
|
finalContent = result.content.substring(0, remainingSpace);
|
||||||
|
wasTruncated = true;
|
||||||
|
} else if (remainingSpace <= 1000) {
|
||||||
|
const fileSizeKB = (file.size / 1024).toFixed(2);
|
||||||
|
ElMessage.error(`${file.name} (${fileSizeKB}KB) 会超过总内容限制,已跳过`);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
totalContentLength += result.content.length;
|
totalContentLength += finalContent.length;
|
||||||
|
|
||||||
arr.push({
|
arr.push({
|
||||||
uid: crypto.randomUUID(),
|
uid: crypto.randomUUID(),
|
||||||
@@ -553,16 +608,17 @@ onChange(async (files) => {
|
|||||||
showDelIcon: true,
|
showDelIcon: true,
|
||||||
imgPreview: false,
|
imgPreview: false,
|
||||||
isUploaded: true,
|
isUploaded: true,
|
||||||
fileContent: result.content,
|
fileContent: finalContent,
|
||||||
fileType: 'text',
|
fileType: 'text',
|
||||||
});
|
});
|
||||||
|
|
||||||
// 提示信息
|
// 提示信息
|
||||||
if (result.totalPages > MAX_PDF_PAGES) {
|
if (wasTruncated) {
|
||||||
ElMessage.warning(`${file.name} 共 ${result.totalPages} 页,已提取前 ${result.extractedPages} 页`);
|
const fileSizeKB = (file.size / 1024).toFixed(2);
|
||||||
|
ElMessage.warning(`${file.name} (${fileSizeKB}KB) 内容过大,已自动截取部分内容`);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`PDF 解析: ${file.name} - 大小: ${(file.size / 1024).toFixed(2)}KB, 总页数: ${result.totalPages}, 已提取: ${result.extractedPages} 页, 内容长度: ${result.content.length} 字符`);
|
console.log(`PDF 解析: ${file.name} - 大小: ${(file.size / 1024).toFixed(2)}KB, 总页数: ${result.totalPages}, 已提取: ${result.extractedPages} 页, 内容长度: ${finalContent.length} 字符`);
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
console.error('解析 PDF 失败:', error);
|
console.error('解析 PDF 失败:', error);
|
||||||
@@ -584,9 +640,14 @@ onChange(async (files) => {
|
|||||||
truncated = true;
|
truncated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查总长度
|
// 动态裁剪内容以适应剩余空间
|
||||||
if (totalContentLength + finalContent.length > MAX_TOTAL_CONTENT_LENGTH) {
|
const remainingSpace = MAX_TOTAL_CONTENT_LENGTH - totalContentLength;
|
||||||
ElMessage.error(`添加 ${file.name} 会超过消息总长度限制(${MAX_TOTAL_CONTENT_LENGTH} 字符),已跳过`);
|
if (finalContent.length > remainingSpace && remainingSpace > 1000) {
|
||||||
|
finalContent = finalContent.substring(0, remainingSpace);
|
||||||
|
truncated = true;
|
||||||
|
} else if (remainingSpace <= 1000) {
|
||||||
|
const fileSizeKB = (file.size / 1024).toFixed(2);
|
||||||
|
ElMessage.error(`${file.name} (${fileSizeKB}KB) 会超过总内容限制,已跳过`);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -607,7 +668,8 @@ onChange(async (files) => {
|
|||||||
|
|
||||||
// 提示信息
|
// 提示信息
|
||||||
if (truncated) {
|
if (truncated) {
|
||||||
ElMessage.warning(`${file.name} 共 ${content.length} 字符,已提取前 ${MAX_TEXT_FILE_LENGTH} 字符`);
|
const fileSizeKB = (file.size / 1024).toFixed(2);
|
||||||
|
ElMessage.warning(`${file.name} (${fileSizeKB}KB) 内容过大,已自动截取部分内容`);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`文本文件读取: ${file.name} - 大小: ${(file.size / 1024).toFixed(2)}KB, 内容长度: ${content.length} 字符`);
|
console.log(`文本文件读取: ${file.name} - 大小: ${(file.size / 1024).toFixed(2)}KB, 内容长度: ${content.length} 字符`);
|
||||||
@@ -627,7 +689,7 @@ onChange(async (files) => {
|
|||||||
|
|
||||||
if (arr.length > 0) {
|
if (arr.length > 0) {
|
||||||
filesStore.setFilesList([...filesStore.filesList, ...arr]);
|
filesStore.setFilesList([...filesStore.filesList, ...arr]);
|
||||||
ElMessage.success(`已添加 ${arr.length} 个文件,当前总内容长度约 ${totalContentLength} 字符`);
|
ElMessage.success(`已添加 ${arr.length} 个文件`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 重置文件选择器
|
// 重置文件选择器
|
||||||
|
|||||||
@@ -274,6 +274,7 @@ async function startSSE(chatContent: string) {
|
|||||||
type: 'image_url',
|
type: 'image_url',
|
||||||
image_url: {
|
image_url: {
|
||||||
url: fileItem.base64, // 使用base64
|
url: fileItem.base64, // 使用base64
|
||||||
|
name: fileItem.name, // 保存图片名称
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -479,7 +480,6 @@ function handleImagePreview(url: string) {
|
|||||||
<Document />
|
<Document />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
<span class="file-name">{{ file.name }}</span>
|
<span class="file-name">{{ file.name }}</span>
|
||||||
<span class="file-size">{{ (file.size / 1024).toFixed(2) }} KB</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 文本内容 -->
|
<!-- 文本内容 -->
|
||||||
|
|||||||
@@ -17,17 +17,101 @@ export const useChatStore = defineStore('chat', () => {
|
|||||||
// 会议ID对应-聊天记录 map对象
|
// 会议ID对应-聊天记录 map对象
|
||||||
const chatMap = ref<Record<string, ChatMessageVo[]>>({});
|
const chatMap = ref<Record<string, ChatMessageVo[]>>({});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析消息内容,提取文本、图片和文件信息
|
||||||
|
* @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(/<ATTACHMENT_FILE>[\s\S]*?<FILE_NAME>(.*?)<\/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(/<ATTACHMENT_FILE>[\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[]) => {
|
const setChatMap = (id: string, data: ChatMessageVo[]) => {
|
||||||
chatMap.value[id] = data?.map((item: ChatMessageVo) => {
|
chatMap.value[id] = data?.map((item: ChatMessageVo) => {
|
||||||
const isUser = item.role === 'user';
|
const isUser = item.role === 'user';
|
||||||
const thinkContent = extractThkContent(item.content as string);
|
|
||||||
|
// 解析消息内容
|
||||||
|
const { text, images, files } = parseMessageContent(item.content as string);
|
||||||
|
|
||||||
|
// 处理思考内容
|
||||||
|
const thinkContent = extractThkContent(text);
|
||||||
|
const finalContent = extractThkContentAfter(text);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
key: item.id,
|
key: item.id,
|
||||||
placement: isUser ? 'end' : 'start',
|
placement: isUser ? 'end' : 'start',
|
||||||
isMarkdown: !isUser,
|
isMarkdown: !isUser,
|
||||||
// variant: 'shadow',
|
|
||||||
// shape: 'corner',
|
|
||||||
avatar: isUser
|
avatar: isUser
|
||||||
? getUserProfilePicture()
|
? getUserProfilePicture()
|
||||||
: systemProfilePicture,
|
: systemProfilePicture,
|
||||||
@@ -35,11 +119,11 @@ export const useChatStore = defineStore('chat', () => {
|
|||||||
typing: false,
|
typing: false,
|
||||||
reasoning_content: thinkContent,
|
reasoning_content: thinkContent,
|
||||||
thinkingStatus: 'end',
|
thinkingStatus: 'end',
|
||||||
content: extractThkContentAfter(item.content as string),
|
content: finalContent,
|
||||||
thinlCollapse: false,
|
thinlCollapse: false,
|
||||||
// 保留图片和文件信息
|
// 保留图片和文件信息(优先使用解析出来的,如果没有则使用原有的)
|
||||||
images: item.images,
|
images: images.length > 0 ? images : item.images,
|
||||||
files: item.files,
|
files: files.length > 0 ? files : item.files,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user