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