125 lines
4.4 KiB
JavaScript
125 lines
4.4 KiB
JavaScript
|
|
#!/usr/bin/env node
|
|||
|
|
/**
|
|||
|
|
* 排查「段落间距」:对比 调用记录里 outline.suggestedContent 与 node_slides.content.paragraphs
|
|||
|
|
* 在服务器上执行(需能连到数据库):
|
|||
|
|
* cd /var/www/wildgrowth-backend/backend && node scripts/inspect-paragraphs-server.js
|
|||
|
|
* 本地(有 .env):
|
|||
|
|
* cd backend && node scripts/inspect-paragraphs-server.js
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
const { PrismaClient } = require('@prisma/client');
|
|||
|
|
const prisma = new PrismaClient();
|
|||
|
|
|
|||
|
|
async function main() {
|
|||
|
|
const argId = process.argv[2] ? process.argv[2].trim() : null;
|
|||
|
|
|
|||
|
|
let task;
|
|||
|
|
if (argId) {
|
|||
|
|
// 先按 taskId 查,再按 courseId 查
|
|||
|
|
task = await prisma.courseGenerationTask.findFirst({
|
|||
|
|
where: { id: argId },
|
|||
|
|
include: { course: { select: { id: true, title: true } } },
|
|||
|
|
});
|
|||
|
|
if (!task) {
|
|||
|
|
task = await prisma.courseGenerationTask.findFirst({
|
|||
|
|
where: { courseId: argId },
|
|||
|
|
orderBy: { createdAt: 'desc' },
|
|||
|
|
include: { course: { select: { id: true, title: true } } },
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
if (!task) {
|
|||
|
|
console.log('未找到 taskId 或 courseId 为', argId, '的任务');
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
// 取最新一条已完成任务
|
|||
|
|
task = await prisma.courseGenerationTask.findFirst({
|
|||
|
|
where: { status: 'completed' },
|
|||
|
|
orderBy: { createdAt: 'desc' },
|
|||
|
|
include: { course: { select: { id: true, title: true } } },
|
|||
|
|
});
|
|||
|
|
if (!task) {
|
|||
|
|
console.log('没有已完成的生成任务');
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
console.log('=== 任务信息 ===');
|
|||
|
|
console.log('taskId:', task.id);
|
|||
|
|
console.log('courseId:', task.courseId);
|
|||
|
|
console.log('courseTitle:', task.course?.title ?? '');
|
|||
|
|
console.log('');
|
|||
|
|
|
|||
|
|
const outline = task.outline;
|
|||
|
|
if (!outline || !outline.chapters || !Array.isArray(outline.chapters)) {
|
|||
|
|
console.log('任务无 outline 或 chapters');
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 取第一个小节对应的 suggestedContent(调用记录里显示的那类内容)
|
|||
|
|
let firstSuggestedContent = null;
|
|||
|
|
let firstNodeTitle = '';
|
|||
|
|
for (const ch of outline.chapters) {
|
|||
|
|
if (ch.nodes && Array.isArray(ch.nodes)) {
|
|||
|
|
for (const node of ch.nodes) {
|
|||
|
|
if (node.suggestedContent) {
|
|||
|
|
firstSuggestedContent = node.suggestedContent;
|
|||
|
|
firstNodeTitle = node.title || '';
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if (firstSuggestedContent) break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!firstSuggestedContent) {
|
|||
|
|
console.log('outline 中未找到 suggestedContent');
|
|||
|
|
} else {
|
|||
|
|
console.log('=== outline 中第一个小节的 suggestedContent(调用记录里看到的内容)===');
|
|||
|
|
console.log('小节标题:', firstNodeTitle);
|
|||
|
|
console.log('长度:', firstSuggestedContent.length);
|
|||
|
|
const idx = firstSuggestedContent.indexOf('\n');
|
|||
|
|
console.log('第一个 \\n 位置:', idx === -1 ? '无' : idx);
|
|||
|
|
const doubleNewlineCount = (firstSuggestedContent.match(/\n\s*\n/g) || []).length;
|
|||
|
|
console.log('双换行 \\n\\n 出现次数:', doubleNewlineCount);
|
|||
|
|
const splitByDouble = firstSuggestedContent.split(/\n\s*\n/).map((p) => p.trim()).filter((p) => p.length > 0);
|
|||
|
|
console.log('按 /\\n\\s*\\n/ 拆分后段落数:', splitByDouble.length);
|
|||
|
|
console.log('前 350 字符(repr):', JSON.stringify(firstSuggestedContent.slice(0, 350)));
|
|||
|
|
console.log('');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 该课程下第一个节点的 node_slides 的 content.paragraphs
|
|||
|
|
const firstNode = await prisma.courseNode.findFirst({
|
|||
|
|
where: { courseId: task.courseId },
|
|||
|
|
orderBy: { orderIndex: 'asc' },
|
|||
|
|
include: { slides: { orderBy: { orderIndex: 'asc' }, take: 1 } },
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
if (!firstNode || !firstNode.slides || firstNode.slides.length === 0) {
|
|||
|
|
console.log('该课程下没有节点或没有 node_slides');
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const slide = firstNode.slides[0];
|
|||
|
|
const content = slide.content;
|
|||
|
|
console.log('=== 该课程第一个节点的 node_slides.content(实际落库)===');
|
|||
|
|
console.log('节点标题:', firstNode.title);
|
|||
|
|
console.log('slide id:', slide.id);
|
|||
|
|
if (content && typeof content === 'object' && Array.isArray(content.paragraphs)) {
|
|||
|
|
console.log('paragraphs 数量:', content.paragraphs.length);
|
|||
|
|
content.paragraphs.forEach((p, i) => {
|
|||
|
|
console.log(` [${i}] 长度: ${p.length}, 前80字: ${JSON.stringify(p.slice(0, 80))}`);
|
|||
|
|
});
|
|||
|
|
} else {
|
|||
|
|
console.log('content 或 content.paragraphs 不存在:', content ? Object.keys(content) : 'null');
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
main()
|
|||
|
|
.then(() => process.exit(0))
|
|||
|
|
.catch((e) => {
|
|||
|
|
console.error(e);
|
|||
|
|
process.exit(1);
|
|||
|
|
})
|
|||
|
|
.finally(() => prisma.$disconnect());
|