实现单篇和多篇论文的对比总结
This commit is contained in:
+65
-31
@@ -1,5 +1,6 @@
|
||||
import type { ChatMessage } from "../llm/types";
|
||||
import { getSummaryPrompt, getSystemPrompt } from "../llm/prompts";
|
||||
import { assemblePaperChatMessages } from "../llm/history";
|
||||
import {
|
||||
buildMetadataBlock,
|
||||
extractPdfContext,
|
||||
@@ -10,6 +11,7 @@ export interface BuiltContext {
|
||||
messages: ChatMessage[];
|
||||
extract: ExtractResult;
|
||||
warning?: string;
|
||||
ready: boolean;
|
||||
}
|
||||
|
||||
export async function buildChatMessages(options: {
|
||||
@@ -23,55 +25,87 @@ export async function buildChatMessages(options: {
|
||||
const warnings: string[] = [];
|
||||
|
||||
if (!extract.text) {
|
||||
return {
|
||||
messages: [],
|
||||
extract,
|
||||
warning:
|
||||
extract.error ||
|
||||
"未能提取 PDF 文本(可能是扫描版或尚无文本层)。请检查附件后重试。",
|
||||
ready: false,
|
||||
};
|
||||
}
|
||||
|
||||
const rawInfo =
|
||||
extract.rawLength && extract.rawLength !== extract.text.length
|
||||
? `(原文 ${extract.rawLength} → 提交 ${extract.text.length})`
|
||||
: "";
|
||||
|
||||
if (extract.truncated) {
|
||||
warnings.push(
|
||||
"未能提取 PDF 文本(可能是扫描版或尚无文本层)。请检查附件后重试。",
|
||||
`已智能截断并优先保留正文${rawInfo},来源 ${extract.source}${
|
||||
extract.pageCount ? ` · ${extract.pageCount} 页` : ""
|
||||
}。`,
|
||||
);
|
||||
} else {
|
||||
warnings.push(
|
||||
`已载入论文文本 ${extract.text.length} 字符(${extract.source}${
|
||||
extract.pageCount ? ` · ${extract.pageCount} 页` : ""
|
||||
})。`,
|
||||
);
|
||||
} else if (extract.truncated) {
|
||||
warnings.push("论文较长,已按设置截断上下文。");
|
||||
}
|
||||
|
||||
const meta = extract.parentItem
|
||||
? buildMetadataBlock(extract.parentItem)
|
||||
: "";
|
||||
|
||||
const systemParts = [getSystemPrompt()];
|
||||
if (meta) {
|
||||
systemParts.push(`论文元数据:\n${meta}`);
|
||||
}
|
||||
if (extract.text) {
|
||||
systemParts.push(
|
||||
`论文正文(页之间可能以换页符分隔):\n${extract.text}`,
|
||||
);
|
||||
}
|
||||
|
||||
const messages: ChatMessage[] = [
|
||||
{ role: "system", content: systemParts.join("\n\n") },
|
||||
];
|
||||
|
||||
// Keep recent history (exclude old system)
|
||||
const history = options.history
|
||||
.filter((m) => m.role !== "system")
|
||||
.slice(-20);
|
||||
messages.push(...history);
|
||||
const paperBlock = [
|
||||
meta ? `【论文元数据】\n${meta}` : "",
|
||||
`【论文正文】\n${extract.text}`,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join("\n\n");
|
||||
|
||||
let taskBlock: string;
|
||||
if (options.mode === "summary") {
|
||||
const summaryAsk = getSummaryPrompt();
|
||||
messages.push({
|
||||
role: "user",
|
||||
content: summaryAsk,
|
||||
});
|
||||
taskBlock = `【任务】
|
||||
请直接基于本会话开头已提供的【论文正文】完成结构化总结。
|
||||
严禁回复「请提供论文」「文本不完整无法总结」等推脱话术;信息不足时也请基于已有正文尽力总结,并简要注明局限。
|
||||
|
||||
${getSummaryPrompt()}`;
|
||||
} else {
|
||||
let content = options.userText.trim();
|
||||
let question = options.userText.trim();
|
||||
if (options.selection?.trim()) {
|
||||
content =
|
||||
`【选中原文】\n${options.selection.trim()}\n\n【问题】\n${content}`;
|
||||
question = `【选中原文】\n${options.selection.trim()}\n\n【问题】\n${question}`;
|
||||
} else {
|
||||
question = `【问题】\n${question}`;
|
||||
}
|
||||
messages.push({ role: "user", content });
|
||||
taskBlock = `【任务】
|
||||
请直接基于本会话开头已提供的论文材料回答。
|
||||
严禁要求用户再次提供论文全文。
|
||||
|
||||
${question}`;
|
||||
}
|
||||
|
||||
const system = `${getSystemPrompt()}
|
||||
|
||||
硬性规则(必须遵守):
|
||||
1. 论文材料已在本会话首条用户消息中提供(【论文正文】);后续每一轮提问仍以该材料为准。
|
||||
2. 绝对禁止说「请提供论文文本」「只有引用/片段无法总结」之类的话。
|
||||
3. 若正文有截断标记,仍须基于已给出的章节作答,并可选一句说明「部分中间内容经抽样」。
|
||||
4. 结合此前对话继续深入回答,不要假装这是全新的、没有论文的会话。
|
||||
5. 不要把参考文献列表误判为「没有正文」。`;
|
||||
|
||||
const messages = assemblePaperChatMessages({
|
||||
system,
|
||||
paperBlock,
|
||||
taskBlock,
|
||||
history: options.history,
|
||||
});
|
||||
|
||||
return {
|
||||
messages,
|
||||
extract,
|
||||
warning: warnings.length ? warnings.join(" ") : undefined,
|
||||
ready: true,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user