Files
chatpapers/src/modules/pdf/context.ts
T

112 lines
3.3 KiB
TypeScript
Raw 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.
import type { ChatMessage } from "../llm/types";
import { getSummaryPrompt, getSystemPrompt } from "../llm/prompts";
import { assemblePaperChatMessages } from "../llm/history";
import {
buildMetadataBlock,
extractPdfContext,
type ExtractResult,
} from "./extractor";
export interface BuiltContext {
messages: ChatMessage[];
extract: ExtractResult;
warning?: string;
ready: boolean;
}
export async function buildChatMessages(options: {
item: Zotero.Item;
history: ChatMessage[];
userText: string;
selection?: string;
mode?: "chat" | "summary";
}): Promise<BuiltContext> {
const extract = await extractPdfContext(options.item);
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(
`已智能截断并优先保留正文${rawInfo},来源 ${extract.source}${
extract.pageCount ? ` · ${extract.pageCount} 页` : ""
}。`,
);
} else {
warnings.push(
`已载入论文文本 ${extract.text.length} 字符(${extract.source}${
extract.pageCount ? ` · ${extract.pageCount} 页` : ""
})。`,
);
}
const meta = extract.parentItem
? buildMetadataBlock(extract.parentItem)
: "";
const paperBlock = [
meta ? `【论文元数据】\n${meta}` : "",
`【论文正文】\n${extract.text}`,
]
.filter(Boolean)
.join("\n\n");
let taskBlock: string;
if (options.mode === "summary") {
taskBlock = `【任务】
请直接基于本会话开头已提供的【论文正文】完成结构化总结。
严禁回复「请提供论文」「文本不完整无法总结」等推脱话术;信息不足时也请基于已有正文尽力总结,并简要注明局限。
${getSummaryPrompt()}`;
} else {
let question = options.userText.trim();
if (options.selection?.trim()) {
question = `【选中原文】\n${options.selection.trim()}\n\n【问题】\n${question}`;
} else {
question = `【问题】\n${question}`;
}
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,
};
}