Files
chatpapers/src/modules/pdf/context.ts
T
2026-07-20 14:40:17 +08:00

78 lines
1.9 KiB
TypeScript

import type { ChatMessage } from "../llm/types";
import { getSummaryPrompt, getSystemPrompt } from "../llm/prompts";
import {
buildMetadataBlock,
extractPdfContext,
type ExtractResult,
} from "./extractor";
export interface BuiltContext {
messages: ChatMessage[];
extract: ExtractResult;
warning?: string;
}
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) {
warnings.push(
"未能提取 PDF 文本(可能是扫描版或尚无文本层)。请检查附件后重试。",
);
} 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);
if (options.mode === "summary") {
const summaryAsk = getSummaryPrompt();
messages.push({
role: "user",
content: summaryAsk,
});
} else {
let content = options.userText.trim();
if (options.selection?.trim()) {
content =
`【选中原文】\n${options.selection.trim()}\n\n【问题】\n${content}`;
}
messages.push({ role: "user", content });
}
return {
messages,
extract,
warning: warnings.length ? warnings.join(" ") : undefined,
};
}