增加pdf中划句或段ai伴读功能

This commit is contained in:
yhy
2026-08-29 23:07:19 +08:00
parent 1475f8b3c5
commit 0ed8f42029
22 changed files with 2045 additions and 15 deletions
@@ -0,0 +1,79 @@
import { parseJsonLoose } from "../../../llm/jsonParse";
import { LlmError } from "../../../llm/types";
import type { SummaryJson } from "../../domain/types";
import { requestStructuredOutput } from "./structuredOutput";
const SENTENCE_SYSTEM = `你是 ChatPapers 论文伴读助手。用户选中论文中的一句原文,需要你解释并用于语音朗读。
必须只输出一个 JSON 对象,不要 markdown 代码块。
格式:{"translation":"...","syntaxNote":"...","contextRole":"..."}
要求:
- translation:准确中文翻译,并用 30–80 字口语解释该句含义(不要念 LaTeX,公式转述为口语)。
- syntaxNote:1–2 句,拆解句法结构或关键术语(英文句为主;中文句可简述逻辑)。
- contextRole:1 句,说明该句在段落或全文论证中的作用。
- 术语翻译与全文保持一致。`;
export interface SentenceLlmResult {
translation: string;
syntaxNote: string;
contextRole: string;
}
function parseSentenceJson(raw: string): SentenceLlmResult {
const parsed = parseJsonLoose<Record<string, unknown>>(raw);
const translation = String(parsed.translation || parsed.zh || "").trim();
if (!translation) {
throw new LlmError("provider", "单句讲解 JSON 缺少 translation 字段。");
}
return {
translation,
syntaxNote: String(parsed.syntaxNote || parsed.syntax || "").trim(),
contextRole: String(parsed.contextRole || parsed.role || parsed.context || "").trim(),
};
}
function fallbackSentence(selectedText: string): SentenceLlmResult {
return {
translation: selectedText.slice(0, 200),
syntaxNote: "",
contextRole: "(模型未能生成上下文说明,请重试或更换模型。)",
};
}
function formatSummaryBlock(summary?: SummaryJson): string {
if (!summary) return "(暂无全文摘要)";
return [
`问题:${summary.problem}`,
`方法:${summary.method}`,
`结果:${summary.result}`,
`局限:${summary.limitation}`,
].join("\n");
}
export async function generateSentenceExplanation(options: {
paperTitle: string;
summary?: SummaryJson;
selectedText: string;
surroundingContext?: string;
}): Promise<SentenceLlmResult> {
const user = `【论文标题】${options.paperTitle}
【全文摘要】
${formatSummaryBlock(options.summary)}
【选区附近上下文(可能为空)】
${options.surroundingContext?.trim() || "(无)"}
【用户选中的句子】
${options.selectedText.trim()}
请输出 JSON。`;
return requestStructuredOutput({
system: SENTENCE_SYSTEM,
user,
parse: parseSentenceJson,
jsonMode: true,
fallback: () => fallbackSentence(options.selectedText),
});
}