001project_wildgrowth/backend/scripts/insertSystemNotesToUserNode...

347 lines
10 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 在有用户笔记的节点插入系统笔记
* 插入10条系统笔记到有用户笔记的节点
*/
import prisma from '../src/utils/prisma';
import { SYSTEM_USER_ID } from '../src/constants';
import { logger } from '../src/utils/logger';
/**
* 确保系统用户存在
*/
async function ensureSystemUser() {
const existingUser = await prisma.user.findUnique({
where: { id: SYSTEM_USER_ID },
});
if (existingUser) {
logger.info('系统用户已存在');
return existingUser;
}
const systemUser = await prisma.user.create({
data: {
id: SYSTEM_USER_ID,
nickname: '系统',
agreementAccepted: true,
},
});
logger.info('系统用户创建成功');
return systemUser;
}
/**
* 查找有用户笔记的节点
*/
async function findNodesWithUserNotes() {
// 查找有用户笔记的节点(排除系统笔记)
const notesWithNodes = await prisma.note.findMany({
where: {
nodeId: { not: null },
userId: { not: SYSTEM_USER_ID }, // 只统计用户笔记
},
select: {
nodeId: true,
},
distinct: ['nodeId'],
take: 10, // 取前10个节点
});
const nodeIds = notesWithNodes
.map((item) => item.nodeId)
.filter((id): id is string => id !== null);
logger.info(`找到 ${nodeIds.length} 个有用户笔记的节点`);
if (nodeIds.length === 0) {
// 如果没有用户笔记,使用"高效沟通的艺术"课程的前两节
logger.info('没有找到用户笔记,使用"高效沟通的艺术"课程的前两节');
const courseId = 'course_vertical_001';
const node1Id = 'node_vertical_001_01';
const node2Id = 'node_vertical_001_02';
const nodes = await prisma.courseNode.findMany({
where: {
id: { in: [node1Id, node2Id] },
},
include: {
course: {
select: {
id: true,
title: true,
},
},
},
});
return nodes;
}
// 获取节点详情
const nodes = await prisma.courseNode.findMany({
where: {
id: { in: nodeIds },
},
include: {
course: {
select: {
id: true,
title: true,
},
},
},
});
return nodes;
}
/**
* 创建系统笔记
*/
async function createSystemNote(data: {
nodeId: string;
courseId: string;
startIndex: number;
length: number;
type: 'highlight' | 'thought';
content?: string;
quotedText: string;
}) {
// 检查是否已存在相同的系统笔记(避免重复创建)
const existing = await prisma.note.findFirst({
where: {
userId: SYSTEM_USER_ID,
nodeId: data.nodeId,
startIndex: data.startIndex,
length: data.length,
type: data.type,
},
});
if (existing) {
logger.info(`系统笔记已存在: ${data.quotedText.substring(0, 20)}...`);
return existing;
}
const note = await prisma.note.create({
data: {
userId: SYSTEM_USER_ID,
courseId: data.courseId,
nodeId: data.nodeId,
startIndex: data.startIndex,
length: data.length,
type: data.type,
content: data.content || '',
quotedText: data.quotedText,
},
});
logger.info(`系统笔记创建成功: ${data.quotedText.substring(0, 20)}...`);
return note;
}
/**
* 主函数
*/
async function main() {
try {
logger.info('开始在有用户笔记的节点插入系统笔记...');
// 1. 确保系统用户存在
await ensureSystemUser();
// 2. 查找有用户笔记的节点
const nodes = await findNodesWithUserNotes();
if (nodes.length === 0) {
logger.info('没有找到有用户笔记的节点');
return;
}
// 3. 为每个节点创建系统笔记
let createdCount = 0;
const targetCount = 10;
for (const node of nodes) {
if (createdCount >= targetCount) {
break;
}
logger.info(`为节点 "${node.title}" 创建系统笔记...`);
// 获取该节点的用户笔记,用于生成系统笔记的位置
const userNotes = await prisma.note.findMany({
where: {
nodeId: node.id,
userId: { not: SYSTEM_USER_ID },
},
orderBy: { createdAt: 'asc' },
take: 5, // 每个节点最多创建5条系统笔记
});
logger.info(`节点 "${node.title}" 有 ${userNotes.length} 条用户笔记`);
// 获取该节点的现有系统笔记,用于创建重叠的笔记
const existingSystemNotes = await prisma.note.findMany({
where: {
nodeId: node.id,
userId: SYSTEM_USER_ID,
},
orderBy: { createdAt: 'asc' },
take: 10,
});
logger.info(`节点 "${node.title}" 现有 ${existingSystemNotes.length} 条系统笔记`);
// 为现有系统笔记创建重叠的笔记如果有有效的startIndex
for (const existingNote of existingSystemNotes) {
if (createdCount >= targetCount) {
break;
}
if (existingNote.startIndex === null || existingNote.length === null) {
continue; // 跳过无效的笔记
}
// 如果 startIndex 是 0说明是测试数据跳过
if (existingNote.startIndex === 0) {
continue;
}
// 创建与现有系统笔记部分重叠的新系统笔记
const overlapStart = existingNote.startIndex + Math.floor(existingNote.length / 2);
const systemNoteLength = Math.max(15, existingNote.length);
const systemNoteQuotedText = existingNote.quotedText
? `${existingNote.quotedText.substring(Math.floor(existingNote.quotedText.length / 2))}(系统补充)`
: '系统笔记内容(重叠测试)';
const type = existingNote.type === 'highlight' ? 'thought' : 'highlight';
const content =
type === 'thought'
? '这是一个系统笔记,用于测试重叠显示逻辑。当与用户笔记重叠时,只显示用户笔记的线段。'
: undefined;
await createSystemNote({
nodeId: node.id,
courseId: node.courseId,
startIndex: overlapStart,
length: systemNoteLength,
type,
content,
quotedText: systemNoteQuotedText,
});
createdCount++;
}
// 如果有用户笔记,为每个用户笔记创建系统笔记(部分重叠,部分不重叠)
if (userNotes.length > 0) {
// 有用户笔记的情况:为每个用户笔记创建系统笔记(部分重叠,部分不重叠)
for (let i = 0; i < userNotes.length && createdCount < targetCount; i++) {
const userNote = userNotes[i];
if (!userNote.startIndex || !userNote.length) {
continue;
}
// 策略1创建与用户笔记部分重叠的系统笔记用于测试重叠逻辑
if (i % 2 === 0 && createdCount < targetCount) {
// 重叠情况:系统笔记从用户笔记中间开始,延伸到后面
const overlapStart = userNote.startIndex + Math.floor(userNote.length / 2);
const systemNoteLength = Math.max(15, userNote.length);
const systemNoteQuotedText = userNote.quotedText
? `${userNote.quotedText.substring(Math.floor(userNote.quotedText.length / 2))}(系统补充)`
: '系统笔记内容(重叠测试)';
const type = 'highlight';
await createSystemNote({
nodeId: node.id,
courseId: node.courseId,
startIndex: overlapStart,
length: systemNoteLength,
type,
quotedText: systemNoteQuotedText,
});
createdCount++;
}
// 策略2创建不重叠的系统笔记在用户笔记前面或后面
if (createdCount < targetCount) {
// 在用户笔记前面创建系统笔记
const beforeStartIndex = Math.max(0, userNote.startIndex - 30);
const beforeLength = Math.min(20, userNote.startIndex - beforeStartIndex);
if (beforeLength > 5) {
const systemNoteQuotedText = '系统笔记:这是不重叠的部分';
const type = Math.random() > 0.5 ? 'thought' : 'highlight';
const content =
type === 'thought'
? '这是一个系统笔记,用于测试非重叠显示逻辑。'
: undefined;
await createSystemNote({
nodeId: node.id,
courseId: node.courseId,
startIndex: beforeStartIndex,
length: beforeLength,
type,
content,
quotedText: systemNoteQuotedText,
});
createdCount++;
}
}
}
}
// ✅ 如果还不够10条直接创建系统笔记不依赖现有笔记
const notesPerNode = Math.ceil(targetCount / nodes.length);
const remainingCount = Math.min(notesPerNode, targetCount - createdCount);
for (let i = 0; i < remainingCount && createdCount < targetCount; i++) {
const startIndex = 100 + i * 50; // 每个笔记间隔50个字符从100开始
const length = 20;
const systemNoteQuotedText = `系统笔记 ${createdCount + 1}:这是不重叠的部分`;
const type = createdCount % 2 === 0 ? 'thought' : 'highlight';
const content =
type === 'thought'
? `系统想法笔记 ${createdCount + 1}:这是一个系统笔记,用于测试非重叠显示逻辑。`
: undefined;
await createSystemNote({
nodeId: node.id,
courseId: node.courseId,
startIndex,
length,
type,
content,
quotedText: systemNoteQuotedText,
});
createdCount++;
}
}
logger.info(`系统笔记创建完成!共创建 ${createdCount} 条系统笔记`);
} catch (error) {
logger.error('创建系统笔记失败:', error);
throw error;
} finally {
await prisma.$disconnect();
}
}
// 运行脚本
main()
.then(() => {
process.exit(0);
})
.catch((error) => {
console.error(error);
process.exit(1);
});