// 从作者【已写正文】抽一段代表性摘录,喂给内容感知型生成器(如书名反推)的 brief 字段。 // 纯函数、无副作用;硬上界 maxChars 控 token,保证首尾都进入摘录。 /** 默认摘录上界(字符数),约束喂给 LLM 的 token 体量。 */ export const DEFAULT_EXCERPT_MAX_CHARS = 1800; /** 首尾之间插入的省略标记,提示中间正文被截去。 */ const ELLIPSIS_MARKER = "\n\n……(中略)……\n\n"; /** * 取正文的代表性摘录: * - 空/纯空白 → 返回 ""。 * - 长度 ≤ maxChars → 原样返回(trim 后)。 * - 超界 → 取「开头一段 + 结尾一段」拼接,中间插省略标记,保证首尾都在。 * 正文预算按 maxChars 均分给首尾两段;返回长度 ≤ maxChars + 标记长度。 */ export function buildManuscriptExcerpt( fullText: string, maxChars: number = DEFAULT_EXCERPT_MAX_CHARS, ): string { const trimmed = fullText.trim(); if (trimmed.length === 0) return ""; if (trimmed.length <= maxChars) return trimmed; // 正文预算(不含标记)均分给首尾,向下取整避免超界。 const headBudget = Math.floor(maxChars / 2); const tailBudget = maxChars - headBudget; const head = trimmed.slice(0, headBudget).trimEnd(); const tail = trimmed.slice(trimmed.length - tailBudget).trimStart(); return `${head}${ELLIPSIS_MARKER}${tail}`; }