diff --git a/paper_writer_service/app/services/paper/complete.py b/paper_writer_service/app/services/paper/complete.py index f88c24d..ca002a1 100644 --- a/paper_writer_service/app/services/paper/complete.py +++ b/paper_writer_service/app/services/paper/complete.py @@ -35,8 +35,10 @@ async def get_paper(paper_id: str, format: str = "md") -> dict[str, Any]: {"n": c.get("final_n") or c.get("temp_n"), "text": c["ref_text"], "kind": c["kind"], "source_doc_id": c["source_doc_id"]} for c in citations ] + brief = loads_json(paper.get("brief_json"), {}) return { "ok": True, "paper_id": paper_id, "title": paper["title"], "status": paper["status"], + "template_key": brief.get("template_key") or "document", "sections": [ {"section_id": s["section_id"], "title": s["title"], "status": s["status"], "word_count": s["word_count"]} for s in sections diff --git a/paper_writer_service/app/services/paper/outline.py b/paper_writer_service/app/services/paper/outline.py index 2bac884..94d9b72 100644 --- a/paper_writer_service/app/services/paper/outline.py +++ b/paper_writer_service/app/services/paper/outline.py @@ -33,6 +33,7 @@ async def propose_paper_outline( format_req: str = "", style: str = "", kb_hints: list[dict[str, Any]] | None = None, + template_key: str = "", ) -> dict[str, Any]: # 1. 知识库线索:优先用调用方传入的 kb_hints,否则现场 search_refs(失败静默降级) hints = list(kb_hints or []) @@ -83,7 +84,7 @@ async def propose_paper_outline( paper_id, title, paper_type, language, format_req, style, dumps_json({ "topic": topic, "requirements": requirements, "length": length, - "kb_hints": hints, + "kb_hints": hints, "template_key": template_key, }), dumps_json({ "title": title, diff --git a/sdk/app/routers/paper.py b/sdk/app/routers/paper.py index b95adf3..ba96997 100644 --- a/sdk/app/routers/paper.py +++ b/sdk/app/routers/paper.py @@ -24,6 +24,7 @@ class PaperTurnRequest(BaseModel): session_id: str text: str paper_id: str | None = None + template_key: str = "" class PaperConfirmRequest(BaseModel): @@ -50,7 +51,7 @@ async def paper_health() -> dict[str, Any]: @router.post("/turns") async def paper_turn(payload: PaperTurnRequest, db: Database = Depends(get_db)) -> dict[str, Any]: - blocks = await agent.handle_turn(db, payload.session_id, payload.text, payload.paper_id) + blocks = await agent.handle_turn(db, payload.session_id, payload.text, payload.paper_id, payload.template_key) return {"ok": True, "blocks": blocks} diff --git a/sdk/app/services/paper/agent.py b/sdk/app/services/paper/agent.py index 218a638..5842a81 100644 --- a/sdk/app/services/paper/agent.py +++ b/sdk/app/services/paper/agent.py @@ -92,15 +92,15 @@ def _missing_brief_keys(brief: dict[str, str]) -> list[str]: # 状态机入口 # --------------------------------------------------------------------------- -async def handle_turn(db, session_id: str, text: str, paper_id: str | None = None) -> list[dict[str, Any]]: +async def handle_turn(db, session_id: str, text: str, paper_id: str | None = None, template_key: str = "") -> list[dict[str, Any]]: """一轮对话:推进状态机并落库助手消息,返回消息的 blocks 列表。""" client = _new_client() if not paper_id: - return await _trigger(db, session_id, text, client) - return await _followup(db, session_id, text, paper_id, client) + return await _trigger(db, session_id, text, client, template_key) + return await _followup(db, session_id, text, paper_id, client, template_key) -async def _trigger(db, session_id: str, text: str, client: PaperMcpClient) -> list[dict[str, Any]]: +async def _trigger(db, session_id: str, text: str, client: PaperMcpClient, template_key: str = "") -> list[dict[str, Any]]: brief = await extract_brief(text) missing = _missing_brief_keys(brief) if missing: @@ -112,7 +112,7 @@ async def _trigger(db, session_id: str, text: str, client: PaperMcpClient) -> li await _write_message(db, session_id, blocks=blocks, text="请补充论文信息") return blocks - outline = await client.call_tool("propose_paper_outline", brief) + outline = await client.call_tool("propose_paper_outline", {**brief, "template_key": template_key}) if not outline.get("ok"): blocks = [_text_block(f"论文大纲生成失败:{outline.get('message', '服务未就绪')},请重试。")] await _write_message(db, session_id, blocks=blocks, text=blocks[0]["html"]) @@ -147,7 +147,7 @@ def _is_cancel_request(text: str) -> bool: return bool(s) and any(w in s for w in _CANCEL_WORDS) -async def _followup(db, session_id: str, text: str, paper_id: str, client: PaperMcpClient) -> list[dict[str, Any]]: +async def _followup(db, session_id: str, text: str, paper_id: str, client: PaperMcpClient, template_key: str = "") -> list[dict[str, Any]]: prog = await client.call_tool("get_paper_progress", {"paper_id": paper_id}) if not prog.get("ok"): blocks = [_text_block(f"未找到论文({paper_id}),请重新发起撰写。")] @@ -172,7 +172,7 @@ async def _followup(db, session_id: str, text: str, paper_id: str, client: Paper if status in ("outline", "writing"): # 大纲/撰写阶段:把 text 视为补充要求,重新生成大纲(原大纲作废) brief = await extract_brief(text) - outline = await client.call_tool("propose_paper_outline", {**brief, "topic": brief.get("topic") or text}) + outline = await client.call_tool("propose_paper_outline", {**brief, "topic": brief.get("topic") or text, "template_key": template_key}) if outline.get("ok"): await client.call_tool("cancel_paper", {"paper_id": paper_id}) return await _outline_message(db, session_id, outline) @@ -289,10 +289,10 @@ async def _artifact_message(db, session_id: str, paper: dict[str, Any], nl: str) refs = paper.get("references") or [] title = paper.get("title", "") full_md = _build_full_markdown(paper) - html, css = templating.render_html(full_md, title=title, key="document") + html, css = templating.render_html(full_md, title=title, key=paper.get("template_key") or "document") artifact_id = await insert_artifact( db, session_id=session_id, title=title, - markdown=full_md, template_name="论文", template_key="document", + markdown=full_md, template_name="论文", template_key=paper.get("template_key") or "document", template_css=css, html=html, ) blocks = [ diff --git a/ui/src/components/chat/Composer.vue b/ui/src/components/chat/Composer.vue index 6ca3741..3abf9a6 100644 --- a/ui/src/components/chat/Composer.vue +++ b/ui/src/components/chat/Composer.vue @@ -13,7 +13,7 @@ // qa → 原 emit('send') 路径(附件注记进消息文本)。 // 路由收敛在本组件内,ChatPanel 等上游组件零改动。 import { ref, computed, onMounted } from 'vue'; -import { MODES as MODE_LABELS, T } from '../../i18n/labels.js'; +import { T } from '../../i18n/labels.js'; import { DG, BUILTIN_TEMPLATES } from '../../i18n/docgen.js'; import { BF } from '../../i18n/bioflow.js'; import { route, paperIntent } from '../../intent.js'; @@ -315,7 +315,7 @@ const submit = () => { } if (paperRoute) { try { - useChatStore().sendPaper(text).catch(() => { + useChatStore().sendPaper(text, { templateId: selectedTemplateId.value || '' }).catch(() => { /* sendPaper 内部已按失败可见原则标注错误 */ }); } catch { @@ -390,18 +390,6 @@ defineExpose({ clear: () => { draft.value = ''; }, focus: () => textarea.value?. @drop="onDrop" >
-
- -
diff --git a/ui/src/components/chat/PaperBriefCard.vue b/ui/src/components/chat/PaperBriefCard.vue index 7bbf872..4fbcb5d 100644 --- a/ui/src/components/chat/PaperBriefCard.vue +++ b/ui/src/components/chat/PaperBriefCard.vue @@ -54,10 +54,10 @@ function submit() {