78 lines
1.9 KiB
TypeScript
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,
|
|
};
|
|
}
|