80 lines
2.6 KiB
TypeScript
80 lines
2.6 KiB
TypeScript
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),
|
|
});
|
|
}
|