forked from admin/PlantAI-rag-new
fix(paper): 确认大纲后即时 seed 进度卡并逐节刷新
- 后端写稿循环不再落空 paper_progress 块(重载后出现空卡),改落开始撰写文本 - 前端 confirmPaper 时用大纲节标题本地 seed 进度卡,2s 轮询 patch 逐节状态 - 当前节按 current_section_id 标 writing(…动画)
This commit is contained in:
@@ -232,9 +232,9 @@ async def run_writing_loop(db, paper_id: str, session_id: str) -> None:
|
||||
from ...routers.docgen import insert_artifact # 惰性导入,避免服务层→路由层常驻耦合
|
||||
|
||||
client = _new_client()
|
||||
await _write_message(db, session_id, blocks=[
|
||||
{"type": "paper_progress", "paper_id": paper_id, "status": "writing", "sections": [], "current_section_id": ""},
|
||||
], text="开始撰写")
|
||||
# 进度卡由前端确认时本地 seed + 2s 轮询 get_paper_progress 驱动(不落库,避免重载后出现
|
||||
# 空的「撰写中」卡);后端只落「开始撰写」文本 + 逐节完成小结 + 最终 artifact。
|
||||
await _write_message(db, session_id, blocks=[_text_block("开始逐节撰写……")], text="开始撰写")
|
||||
try:
|
||||
while True:
|
||||
prog = await client.call_tool("get_paper_progress", {"paper_id": paper_id})
|
||||
|
||||
@@ -118,6 +118,7 @@ def test_writing_loop_completes_to_artifact(bff_database, monkeypatch, fake_inse
|
||||
|
||||
assert svc.s1_done and svc.s2_done
|
||||
rows = _run(bff_database.fetchall("SELECT * FROM messages WHERE session_id = 's1' ORDER BY rowid"))
|
||||
assert "paper_progress" in rows[0]["blocks"]
|
||||
# 进度卡由前端确认时本地 seed + 轮询驱动,后端只落「开始撰写」文本 + 逐节小结 + artifact
|
||||
assert "开始逐节撰写" in rows[0]["blocks"]
|
||||
assert "artifact" in rows[-1]["blocks"]
|
||||
assert "art-fake" in rows[-1]["blocks"]
|
||||
|
||||
+39
-3
@@ -1658,16 +1658,47 @@ export const useChatStore = defineStore('chat', {
|
||||
this.scrollSeq++;
|
||||
},
|
||||
|
||||
/** 确认大纲 → POST confirm 启动后台写节循环 → 2s 轮询进度 */
|
||||
/** 确认大纲 → 本地先 seed 进度卡 → POST confirm 启动后台写节循环 → 2s 轮询进度 */
|
||||
async confirmPaper(paperId) {
|
||||
const sessionId = this.sessionId;
|
||||
if (!paperId || !sessionId) return;
|
||||
this._seedPaperProgress(sessionId, paperId);
|
||||
try {
|
||||
await confirmPaperApi(paperId, sessionId);
|
||||
} catch { /* 启动失败:卡片可见错误 */ }
|
||||
this._startPaperPoll(paperId, sessionId);
|
||||
},
|
||||
|
||||
/** 确认后立即在消息流上一条 paper_progress 块(用大纲节标题做种子,全部 pending),
|
||||
* 使 _startPaperPoll 的 _patchPaperProgress 有块可 patch,进度卡在撰写期间逐节刷新,
|
||||
* 而不是等 complete 重载时一次性出现。 */
|
||||
_seedPaperProgress(sessionId, paperId) {
|
||||
const list = this.sessionMsgs[sessionId] || this.messages || [];
|
||||
for (const m of list) {
|
||||
if (!m || m.role !== 'assistant' || !Array.isArray(m.blocks)) continue;
|
||||
if (m.blocks.some((b) => b && b.type === 'paper_progress' && b.paper_id === paperId)) return;
|
||||
}
|
||||
let sections = [];
|
||||
for (let i = list.length - 1; i >= 0; i--) {
|
||||
const m = list[i];
|
||||
if (!m || m.role !== 'assistant' || !Array.isArray(m.blocks)) continue;
|
||||
const ob = m.blocks.find((b) => b && b.type === 'paper_outline' && b.paper_id === paperId);
|
||||
if (ob) {
|
||||
sections = (Array.isArray(ob.sections) ? ob.sections : []).map((sec) => ({
|
||||
section_id: sec.section_id, title: sec.title || '', status: 'pending',
|
||||
}));
|
||||
break;
|
||||
}
|
||||
}
|
||||
const raw = {
|
||||
id: null, role: 'assistant', kind: 'paper', status: 'done', text: null,
|
||||
blocks: [{ type: 'paper_progress', paper_id: paperId, status: 'writing', sections, current_section_id: '' }],
|
||||
raw: null, created_at: new Date().toISOString(), updated_at: new Date().toISOString(),
|
||||
};
|
||||
list.push(raw);
|
||||
this.scrollSeq++;
|
||||
},
|
||||
|
||||
_startPaperPoll(paperId, sessionId) {
|
||||
if (paperPolls.has(paperId)) return;
|
||||
const entry = { timer: null, sessionId };
|
||||
@@ -1706,13 +1737,18 @@ export const useChatStore = defineStore('chat', {
|
||||
/** 把进度同步进消息流里的 paper_progress 块 */
|
||||
_patchPaperProgress(sessionId, prog) {
|
||||
const list = this.sessionMsgs[sessionId] || [];
|
||||
const current = prog.current_section_id || '';
|
||||
for (const m of list) {
|
||||
if (!m || m.role !== 'assistant' || !Array.isArray(m.blocks)) continue;
|
||||
const pb = m.blocks.find((b) => b && b.type === 'paper_progress');
|
||||
if (pb) {
|
||||
pb.status = prog.status;
|
||||
pb.current_section_id = prog.current_section_id || '';
|
||||
pb.sections = (prog.sections || []).map((s) => ({ section_id: s.section_id, title: s.title, status: s.status }));
|
||||
pb.current_section_id = current;
|
||||
// 后端节状态只有 pending/done;当前节用 current_section_id 标为 writing(…动画)
|
||||
pb.sections = (prog.sections || []).map((sec) => ({
|
||||
section_id: sec.section_id, title: sec.title,
|
||||
status: (current && sec.section_id === current) ? 'writing' : sec.status,
|
||||
}));
|
||||
}
|
||||
}
|
||||
this.scrollSeq++;
|
||||
|
||||
Reference in New Issue
Block a user