Files
PlantAI-rag-new/deploy/m2_probe.js
jerryandClaude Fable 5 1e94de7464 PlantAI-rag-new 首次提交:文献知识工作台
- BFF 薄适配层(FastAPI,8090):QA 代理/SSE 中继/Neo4j 直连/抽取代理/会话持久化
- Vue3 前端:五相位检索流水线、文献来源与证据链、知识图谱、提取任务四 tab
- 四档响应式(桌面/笔记本/平板/手机)、深浅主题
- 81 个 FR 全部实现,测试追溯矩阵 81/81,后端 121 测/前端 156 测
- 真实凭据已脱敏,运行时配置在 backend/.env(不入 git)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 20:47:52 +08:00

69 lines
3.2 KiB
JavaScript
Raw Permalink 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.
// deploy/m2_probe.js —— 诊断探针(PM 使用,在远端运行)
// 目的:定位真实浏览器中 SSE progress 未推进流水线相位的原因
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
const ctx = await browser.newContext({ viewport: { width: 1440, height: 900 } });
const page = await ctx.newPage();
const logs = [];
page.on('console', (m) => {
if (m.type() === 'error' || m.type() === 'warning') logs.push(`[${m.type()}] ${m.text().slice(0, 200)}`);
});
page.on('pageerror', (e) => logs.push('[pageerror] ' + e.message.slice(0, 200)));
await page.goto('http://127.0.0.1:5180', { waitUntil: 'domcontentloaded' });
await page.waitForSelector('.app-shell', { timeout: 15000 });
await page.click('.new-task-btn');
await page.waitForSelector('.composer textarea', { timeout: 15000 });
// 用「检索」模式(use_llm:false,走 /api/qa/search,更快的真实链路)排除揭示动画干扰
// 但 search 无 SSE——这里仍用默认问答走 SSE,只是探针只观察 60s
await page.fill('.composer textarea', 'SPL gene family in rice');
await page.click('.send-btn');
const t0 = Date.now();
const timeline = [];
let pipelineSeen = false;
while (Date.now() - t0 < 90000) {
const snap = await page.evaluate(() => {
const card = document.querySelector('.pipeline-card');
const steps = Array.from(document.querySelectorAll('.pipeline-card .p-step'));
const msgs = Array.from(document.querySelectorAll('.msg.assistant'));
const stream = document.querySelector('.stream-text')?.textContent?.length || 0;
const body = document.querySelector('.msg.assistant .msg-body')?.textContent?.length || 0;
// 检查正在进行的 fetch 到 stream 端点
const perf = performance.getEntriesByType('resource').filter((r) => r.name.includes('chat/stream'));
return {
card: !!card,
stepCount: steps.length,
states: steps.map((s) => (s.className.includes('done') ? 'D' : s.className.includes('running') ? 'R' : 'W')).join(''),
descs: steps.map((s) => s.querySelector('.p-desc')?.textContent?.slice(0, 20)).join('|'),
msgCount: msgs.length,
streamLen: stream,
bodyLen: body,
streamReqs: perf.length,
};
});
const key = JSON.stringify(snap);
if (!timeline.length || timeline[timeline.length - 1].key !== key) {
timeline.push({ t: Math.round((Date.now() - t0) / 1000), key });
console.log(`T+${Math.round((Date.now() - t0) / 1000)}s`, JSON.stringify(snap));
}
if (snap.card) pipelineSeen = true;
if (snap.bodyLen > 30 && snap.streamLen === 0 && snap.states.includes('D')) break;
if (snap.bodyLen > 50) break; // 答案已出现,看相位是否 done
await new Promise((r) => setTimeout(r, 2000));
}
console.log('\n--- 浏览器日志(error/warning)---');
logs.slice(0, 10).forEach((l) => console.log(l));
console.log('\n--- 最终 DOM 摘要 ---');
const fin = await page.evaluate(() => {
const card = document.querySelector('.pipeline-card');
return card ? card.outerHTML.slice(0, 1200) : '无 pipeline-card';
});
console.log(fin);
await browser.close();
})();