001project_wildgrowth/backend/scripts/insertSystemNotesToUserNode...

347 lines
10 KiB
TypeScript
Raw Normal View History

2026-02-11 15:26:03 +08:00
/**
*
* 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);
});