| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127 |
- // e2e-verify-model-switch.js
- // 实际数据库连接,验证扫描器/状态机/供应商切换
- const { PrismaClient } = require('@prisma/client');
- // 从 server/.env 加载 DATABASE_URL
- const fs = require('fs');
- const path = require('path');
- try {
- const envPath = path.resolve(__dirname, '../../server/.env');
- const envContent = fs.readFileSync(envPath, 'utf-8');
- for (const line of envContent.split('\n')) {
- const m = line.match(/^([A-Z_][A-Z0-9_]*)=(.*)$/);
- if (m && !process.env[m[1]]) {
- process.env[m[1]] = m[2].replace(/^["']|["']$/g, '');
- }
- }
- } catch (e) {
- console.warn('未找到 .env, 依靠环境变量');
- }
- const p = new PrismaClient();
- (async () => {
- try {
- // 1. 找到当前数据库所有供应商状态
- console.log('=== 1. 当前供应商状态 ===');
- const recentBooks = await p.book.findMany({
- where: { createdAt: { gte: new Date(Date.now() - 60 * 60 * 1000) } },
- select: { id: true, title: true, genStage: true, errorMsg: true, updatedAt: true, createdAt: true },
- orderBy: { createdAt: 'desc' },
- take: 10,
- });
- if (recentBooks.length === 0) {
- console.log(' 没有最近 1 小时的书,等待真实数据...');
- // 看最近 24 小时的
- const allBooks = await p.book.findMany({
- select: { id: true, title: true, genStage: true, errorMsg: true, updatedAt: true, createdAt: true },
- orderBy: { createdAt: 'desc' },
- take: 10,
- });
- console.log(` 最近 10 本书 (24h+):`);
- for (const b of allBooks) {
- console.log(` - #${b.id} "${b.title.slice(0, 30)}..." stage=${b.genStage} err=${b.errorMsg ? b.errorMsg.slice(0, 80) : 'null'}`);
- }
- } else {
- console.log(` 最近 1 小时 ${recentBooks.length} 本书:`);
- for (const b of recentBooks) {
- console.log(` - #${b.id} "${b.title.slice(0, 30)}..." stage=${b.genStage} err=${b.errorMsg ? b.errorMsg.slice(0, 80) : 'null'}`);
- }
- }
- // 2. 检查 failed 章节情况
- console.log('\n=== 2. 失败章节统计 ===');
- const failedChapters = await p.bookChapter.groupBy({
- by: ['genStage'],
- _count: { genStage: true },
- where: { contentError: { not: null } },
- });
- for (const f of failedChapters) {
- console.log(` ${f.genStage}: ${f._count.genStage}`);
- }
- // 3. 检查 scan log 来推断恢复情况
- console.log('\n=== 3. 看最近 5 个 failed 章节的内容错误 ===');
- const failedSamples = await p.bookChapter.findMany({
- where: { contentError: { not: null } },
- select: { id: true, bookId: true, title: true, contentError: true, updatedAt: true },
- orderBy: { updatedAt: 'desc' },
- take: 5,
- });
- for (const c of failedSamples) {
- console.log(` ch#${c.id} (book ${c.bookId}) "${c.title.slice(0, 30)}":`);
- console.log(` err: ${(c.contentError || '').slice(0, 200)}`);
- console.log(` updatedAt: ${c.updatedAt.toISOString()}`);
- }
- // 4. 验证 recovery scanner 是否在工作
- console.log('\n=== 4. 检查扫描器状态 ===');
- const stuckBooks = await p.book.count({
- where: {
- genStage: 'content_generating',
- updatedAt: { lt: new Date(Date.now() - 30 * 60 * 1000) }, // 30分钟没动
- },
- });
- console.log(` 卡在 content_generating 超过 30 分钟的书: ${stuckBooks}`);
- const outlineReadyBooks = await p.book.count({
- where: {
- genStage: 'outline_ready',
- updatedAt: { lt: new Date(Date.now() - 15 * 60 * 1000) }, // 15分钟没动
- },
- });
- console.log(` 卡在 outline_ready 超过 15 分钟的书: ${outlineReadyBooks}`);
- // 5. 健康总结
- console.log('\n=== 5. 健康总结 ===');
- const healthCheck = {
- noCrash: true, // 如果到这里没崩就算
- recoverableBooks: 0,
- totalFailedChapters: failedSamples.length,
- stuckBooks,
- has429Evidence: false,
- };
- // 检测是否有过 429
- for (const c of failedSamples) {
- if (c.contentError && /429|quota|usage|rate limit|insufficient/i.test(c.contentError)) {
- healthCheck.has429Evidence = true;
- break;
- }
- }
- console.log(` 进程存活: ✅`);
- console.log(` 失败章节总数: ${healthCheck.totalFailedChapters}`);
- console.log(` 卡住的书籍: ${healthCheck.stuckBooks}`);
- console.log(` 看到过 429 证据: ${healthCheck.has429Evidence ? '⚠️ 是' : '✅ 否'}`);
- } catch (err) {
- console.error('❌ 测试异常:', err.message);
- process.exit(1);
- } finally {
- await p.$disconnect();
- }
- })();
|