134 lines
3.4 KiB
JavaScript
134 lines
3.4 KiB
JavaScript
|
|
/**
|
|||
|
|
* Chunk合并工具函数
|
|||
|
|
* 用于合并多个chunk并处理重叠内容
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 查找两个字符串的重叠部分
|
|||
|
|
* @param {string} str1 - 第一个字符串
|
|||
|
|
* @param {string} str2 - 第二个字符串
|
|||
|
|
* @returns {string} - 重叠部分的内容
|
|||
|
|
*/
|
|||
|
|
export function findOverlap(str1, str2) {
|
|||
|
|
if (!str1 || !str2) return '';
|
|||
|
|
|
|||
|
|
const maxOverlap = Math.min(str1.length, str2.length);
|
|||
|
|
let overlap = '';
|
|||
|
|
|
|||
|
|
// 从最长可能的重叠开始检查
|
|||
|
|
for (let i = maxOverlap; i > 0; i--) {
|
|||
|
|
const endStr1 = str1.slice(-i);
|
|||
|
|
const startStr2 = str2.slice(0, i);
|
|||
|
|
|
|||
|
|
if (endStr1 === startStr2) {
|
|||
|
|
overlap = endStr1;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return overlap;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 合并chunks并处理重叠内容
|
|||
|
|
* @param {Array} chunks - chunk数组,每个chunk包含id, content, chunk_order_index
|
|||
|
|
* @returns {Object} - 合并结果,包含content和chunks数组
|
|||
|
|
*/
|
|||
|
|
export function mergeChunks(chunks) {
|
|||
|
|
if (!chunks || chunks.length === 0) {
|
|||
|
|
return { content: '', chunks: [] };
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 按order排序
|
|||
|
|
const sorted = [...chunks].sort((a, b) => a.chunk_order_index - b.chunk_order_index);
|
|||
|
|
const merged = [];
|
|||
|
|
let currentContent = '';
|
|||
|
|
|
|||
|
|
for (let i = 0; i < sorted.length; i++) {
|
|||
|
|
const chunk = sorted[i];
|
|||
|
|
const content = chunk.content;
|
|||
|
|
|
|||
|
|
if (i === 0) {
|
|||
|
|
// 第一个chunk直接添加
|
|||
|
|
currentContent = content;
|
|||
|
|
merged.push({
|
|||
|
|
...chunk,
|
|||
|
|
startOffset: 0,
|
|||
|
|
endOffset: content.length
|
|||
|
|
});
|
|||
|
|
} else {
|
|||
|
|
// 查找重叠部分
|
|||
|
|
const overlap = findOverlap(currentContent, content);
|
|||
|
|
const newContent = content.slice(overlap.length);
|
|||
|
|
|
|||
|
|
if (newContent.length > 0) {
|
|||
|
|
const startOffset = currentContent.length;
|
|||
|
|
currentContent += newContent;
|
|||
|
|
merged.push({
|
|||
|
|
...chunk,
|
|||
|
|
startOffset,
|
|||
|
|
endOffset: currentContent.length
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return { content: currentContent, chunks: merged };
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 将文本分割成段落
|
|||
|
|
* @param {string} content - 文本内容
|
|||
|
|
* @returns {Array} - 段落数组
|
|||
|
|
*/
|
|||
|
|
export function splitIntoParagraphs(content) {
|
|||
|
|
if (!content) return [];
|
|||
|
|
|
|||
|
|
// 按换行符分割,保留空段落
|
|||
|
|
return content.split(/\n\n+/).filter(para => para.trim() !== '');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 为每个段落找到对应的chunk
|
|||
|
|
* @param {Array} paragraphs - 段落数组
|
|||
|
|
* @param {Array} mappedChunks - 映射后的chunks
|
|||
|
|
* @returns {Array} - 包含chunk信息的段落
|
|||
|
|
*/
|
|||
|
|
export function mapParagraphsToChunks(paragraphs, mappedChunks) {
|
|||
|
|
if (!paragraphs || !mappedChunks) return [];
|
|||
|
|
|
|||
|
|
let currentOffset = 0;
|
|||
|
|
return paragraphs.map(paragraph => {
|
|||
|
|
const paragraphLength = paragraph.length + 2; // +2 for the \n\n
|
|||
|
|
|
|||
|
|
// 找到包含此位置的chunk
|
|||
|
|
const chunk = mappedChunks.find(chunk =>
|
|||
|
|
currentOffset >= chunk.startOffset && currentOffset < chunk.endOffset
|
|||
|
|
) || mappedChunks[0];
|
|||
|
|
|
|||
|
|
const result = {
|
|||
|
|
content: paragraph,
|
|||
|
|
chunk,
|
|||
|
|
startOffset: currentOffset,
|
|||
|
|
endOffset: currentOffset + paragraphLength
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
currentOffset += paragraphLength;
|
|||
|
|
return result;
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 获取chunk的预览文本
|
|||
|
|
* @param {string} content - chunk内容
|
|||
|
|
* @param {number} maxLength - 最大长度
|
|||
|
|
* @returns {string} - 预览文本
|
|||
|
|
*/
|
|||
|
|
export function getChunkPreview(content, maxLength = 100) {
|
|||
|
|
if (!content) return '';
|
|||
|
|
|
|||
|
|
const text = content.replace(/\n+/g, ' ').trim();
|
|||
|
|
if (text.length <= maxLength) return text;
|
|||
|
|
|
|||
|
|
return text.slice(0, maxLength) + '...';
|
|||
|
|
}
|