Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 | /**
* 内容一致性跟踪器(事中预防)
*
* 解决 issue:质量检查是"事后纠错",问题发现得晚,rewrite 成本高。
*
* 在内容生成过程中维护一个运行中的"全书术语表/关键概念档案",
* 每章生成后自动校验关键术语和逻辑是否一致,发现问题可即时触发修正。
*
* 核心思路:
* - 逐章/逐节生成时,提取并缓存关键术语、定义、角色设定
* - 后续章节生成后,快速比对缓存中的术语定义是否一致
* - 发现冲突立即记录,生成完成后汇总报告
*/
/** 术语定义记录 */
export interface TermRecord {
term: string; // 术语/概念名
definition: string; // 定义/描述
firstChapter: number; // 首次出现的章节号
chapterOccurrences: number[]; // 出现的章节号列表
}
/** 一致性检查结果 */
export interface ConsistencyIssue {
type: 'conflicting_definition' | 'missing_definition' | 'inconsistent_naming' | 'logical_contradiction';
severity: 'high' | 'medium' | 'low';
term: string;
chapterA: number;
chapterB?: number;
description: string;
}
/** 一致性报告 */
export interface ConsistencyReport {
terms: TermRecord[];
issues: ConsistencyIssue[];
hasConflicts: boolean;
}
export class BookConsistencyTracker {
private terms: Map<string, TermRecord> = new Map();
private chapterContentCache: Map<number, string> = new Map();
private issues: ConsistencyIssue[] = [];
/**
* 记录一个新生成的章节内容,提取关键术语。
*/
registerChapter(
chapterNumber: number,
chapterTitle: string,
content: string
): void {
this.chapterContentCache.set(chapterNumber, content);
// 简单正则提取可能的术语定义模式(中文常见格式)
// 模式1:xxx 是指 / xxx 指的是 / xxx 定义为
const definitionPatterns = [
/([^\s,,。.;;]{2,15})[((]([^))]{2,20})[))]/g, // 术语(英文/缩写)
/([^\s,,。.;;]{2,20})(?:是指|指的是|定义为|即|也就是|意为)\s*([^\s,,。.;;]{2,30})/g, // 术语是指xxx
];
for (const pattern of definitionPatterns) {
let match: RegExpExecArray | null;
while ((match = pattern.exec(content)) !== null) {
const term = match[1].trim();
const definition = match[2].trim();
// 过滤太短的噪声
if (term.length < 2 || definition.length < 1) continue;
const existing = this.terms.get(term);
if (existing) {
existing.chapterOccurrences.push(chapterNumber);
// 检查定义是否冲突
if (existing.definition !== definition &&
this.levenshteinSimilarity(existing.definition, definition) < 0.6) {
this.issues.push({
type: 'conflicting_definition',
severity: 'high',
term,
chapterA: existing.firstChapter,
chapterB: chapterNumber,
description: `术语"${term}"在第${existing.firstChapter}章定义为"${existing.definition}",第${chapterNumber}章定义为"${definition}",差异较大`,
});
}
} else {
this.terms.set(term, {
term,
definition,
firstChapter: chapterNumber,
chapterOccurrences: [chapterNumber],
});
}
}
}
}
/**
* 获取全书术语摘要,可嵌入后续章节的提示词中
* @param maxTerms 最多返回的术语数
* @param currentChapter 当前正在生成的章节号(排除该章自身的术语)
*/
getTermContext(maxTerms: number = 20, currentChapter?: number): string {
const entries = Array.from(this.terms.values())
.filter(t => currentChapter === undefined || !t.chapterOccurrences.includes(currentChapter))
.slice(0, maxTerms);
if (entries.length === 0) return '';
const lines = entries.map(t =>
`- ${t.term}:${t.definition}(见第${t.firstChapter}章)`
);
return `\n## 已建立的关键概念/术语(请保持一致定义)\n${lines.join('\n')}`;
}
/**
* 获取所有发现的一致性问题
*/
getIssues(): ConsistencyIssue[] {
return [...this.issues];
}
/**
* 生成完整的术语一致性报告
*/
generateReport(): ConsistencyReport {
return {
terms: Array.from(this.terms.values()),
issues: [...this.issues],
hasConflicts: this.issues.length > 0,
};
}
/**
* 简单字符串相似度(Levenshtein 距离比)
*/
private levenshteinSimilarity(a: string, b: string): number {
const maxLen = Math.max(a.length, b.length);
if (maxLen === 0) return 1;
const distance = this.levenshteinDistance(a, b);
return 1 - distance / maxLen;
}
private levenshteinDistance(a: string, b: string): number {
const matrix: number[][] = [];
for (let i = 0; i <= a.length; i++) {
matrix[i] = [i];
}
for (let j = 0; j <= b.length; j++) {
matrix[0][j] = j;
}
for (let i = 1; i <= a.length; i++) {
for (let j = 1; j <= b.length; j++) {
if (a[i - 1] === b[j - 1]) {
matrix[i][j] = matrix[i - 1][j - 1];
} else {
matrix[i][j] = Math.min(
matrix[i - 1][j] + 1,
matrix[i][j - 1] + 1,
matrix[i - 1][j - 1] + 1
);
}
}
}
return matrix[a.length][b.length];
}
}
|