(existing: string, continuation: string)
| 602 | * 算法:从续写内容的头部取不同长度的前缀,检查是否出现在原内容的尾部 |
| 603 | */ |
| 604 | export function deduplicateContinuation(existing: string, continuation: string): string { |
| 605 | if (!continuation || !existing) return continuation; |
| 606 | |
| 607 | // 对比窗口:取原内容尾部和续写头部的最大重叠检测范围 |
| 608 | const maxOverlap = Math.min(500, existing.length, continuation.length); |
| 609 | if (maxOverlap < 10) return continuation; // 太短不值得去重 |
| 610 | |
| 611 | const tail = existing.slice(-maxOverlap); |
| 612 | |
| 613 | // 从长到短搜索重叠:找最长的匹配 |
| 614 | let bestOverlap = 0; |
| 615 | for (let len = maxOverlap; len >= 10; len--) { |
| 616 | const prefix = continuation.substring(0, len); |
| 617 | // 检查 prefix 是否出现在 tail 的末尾 |
| 618 | if (tail.endsWith(prefix)) { |
| 619 | bestOverlap = len; |
| 620 | break; |
| 621 | } |
| 622 | } |
| 623 | |
| 624 | // 如果没找到尾部完全匹配的重叠,尝试行级别的去重 |
| 625 | // 场景:模型从某一行的开头重新开始,但截断点可能在行中间 |
| 626 | if (bestOverlap === 0) { |
| 627 | const continuationLines = continuation.split('\n'); |
| 628 | const tailLines = tail.split('\n'); |
| 629 | |
| 630 | // 从续写的第一行开始,在原内容尾部的行中寻找匹配 |
| 631 | if (continuationLines.length > 0 && tailLines.length > 0) { |
| 632 | const firstContLine = continuationLines[0].trim(); |
| 633 | if (firstContLine.length >= 10) { |
| 634 | // 检查续写的前几行是否在原内容尾部出现过 |
| 635 | for (let i = tailLines.length - 1; i >= 0; i--) { |
| 636 | if (tailLines[i].trim() === firstContLine) { |
| 637 | // 从这一行开始往后对比连续匹配的行数 |
| 638 | let matchedLines = 1; |
| 639 | for (let k = 1; k < continuationLines.length && i + k < tailLines.length; k++) { |
| 640 | if (continuationLines[k].trim() === tailLines[i + k].trim()) { |
| 641 | matchedLines++; |
| 642 | } else { |
| 643 | break; |
| 644 | } |
| 645 | } |
| 646 | if (matchedLines >= 2) { |
| 647 | // 移除续写中匹配的行 |
| 648 | const deduped = continuationLines.slice(matchedLines).join('\n'); |
| 649 | // 行级去重记录到详细日志 |
| 650 | return deduped; |
| 651 | } |
| 652 | break; |
| 653 | } |
| 654 | } |
| 655 | } |
| 656 | } |
| 657 | } |
| 658 | |
| 659 | if (bestOverlap > 0) { |
| 660 | return continuation.substring(bestOverlap); |
| 661 | } |
no outgoing calls
no test coverage detected