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 { 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, }; }