Files
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

51 lines
2.1 KiB
JavaScript

// deploy/m2_probe3.js —— 浏览器 fetch chunk 级探针(PM 使用,在远端运行)
// 目的:确定 progress 帧丢失发生在哪一层(Vite proxy 缓冲?fetch 读取?parser?)
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();
// 在页面上下文里直接发起 fetch 并记录 chunk 到达时间线与内容
const result = await page.evaluate(async () => {
const t0 = Date.now();
const log = [];
const ctrl = new AbortController();
const timeout = setTimeout(() => ctrl.abort(), 90000);
try {
const resp = await fetch('http://127.0.0.1:5180/api/qa/chat/stream', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
question: 'SPL gene family in rice',
use_llm: true, debug: false,
chain_top_k: 3, chain_hops: 2, chain_max_edges: 12, chain_max_nodes: 10,
native_chain_enabled: true, native_chain_max_hops: 3, native_chain_top_k: 5,
}),
signal: ctrl.signal,
});
log.push(`T+${Math.round((Date.now() - t0) / 1000)}s headers: status=${resp.status} ct=${resp.headers.get('content-type')}`);
const reader = resp.body.getReader();
const decoder = new TextDecoder();
let nChunks = 0;
for (;;) {
const { done, value } = await reader.read();
if (done) break;
nChunks++;
const text = decoder.decode(value, { stream: true });
const events = (text.match(/event: \w+/g) || []).join(',');
log.push(`T+${Math.round((Date.now() - t0) / 1000)}s chunk#${nChunks} len=${value.length} [${events}] preview=${text.slice(0, 80).replace(/\n/g, '↵')}`);
}
log.push(`T+${Math.round((Date.now() - t0) / 1000)}s stream done, ${nChunks} chunks total`);
} catch (e) {
log.push(`ERROR: ${e.name}: ${e.message}`);
}
clearTimeout(timeout);
return log;
});
result.forEach((l) => console.log(l));
await browser.close();
})();