diff --git a/src/modules/lecture/infrastructure/llm/beatLlm.ts b/src/modules/lecture/infrastructure/llm/beatLlm.ts index 1210922..fa41ede 100644 --- a/src/modules/lecture/infrastructure/llm/beatLlm.ts +++ b/src/modules/lecture/infrastructure/llm/beatLlm.ts @@ -1,6 +1,7 @@ import { LlmError } from "../../../llm/types"; import type { BeatType, SummaryJson } from "../../domain/types"; import type { StoredBeat } from "../storage/lectureStore"; +import { FORCE_ZH_EXPLANATION } from "./promptRules"; import { parseJsonLoose, requestStructuredOutput } from "./structuredOutput"; const VALID_TYPES = new Set([ @@ -17,7 +18,9 @@ const BEATS_SYSTEM = `你是 ChatPapers 语音伴读的备课助手。根据论 要求: - beats 数组含 6–10 项,按教学逻辑:问题引入 → 核心方法 → 关键实验/证据 → 结论与局限 - script 为中文口语,每段 80–180 字,适合朗读;不要念公式符号,用白话解释 -- type 只能是 intro / method / experiment / conclusion / extension`; +- type 只能是 intro / method / experiment / conclusion / extension + +${FORCE_ZH_EXPLANATION}`; interface BeatJson { title?: string; diff --git a/src/modules/lecture/infrastructure/llm/lectureLlm.ts b/src/modules/lecture/infrastructure/llm/lectureLlm.ts index 1e9ca76..797c866 100644 --- a/src/modules/lecture/infrastructure/llm/lectureLlm.ts +++ b/src/modules/lecture/infrastructure/llm/lectureLlm.ts @@ -2,12 +2,15 @@ import { getRuntimeConfig } from "../../../llm/client"; import { parseJsonLoose, parseLabeledFields } from "../../../llm/jsonParse"; import { LlmError } from "../../../llm/types"; import type { SummaryJson } from "../../domain/types"; +import { FORCE_ZH_EXPLANATION } from "./promptRules"; import { requestStructuredOutput } from "./structuredOutput"; const SUMMARY_SYSTEM = `你是 ChatPapers 语音伴读的备课助手。根据论文正文生成结构化摘要。 必须只输出一个 JSON 对象,不要 markdown 代码块,不要其他说明。 格式:{"problem":"...","method":"...","result":"...","limitation":"..."} -每项 1-3 句中文,准确、简洁,基于正文,不要编造。`; +每项 1-3 句中文,准确、简洁,基于正文,不要编造。 + +${FORCE_ZH_EXPLANATION}`; const SUMMARY_LABELS = [ { field: "problem", labels: ["问题", "研究问题", "problem"] }, diff --git a/src/modules/lecture/infrastructure/llm/paragraphLlm.ts b/src/modules/lecture/infrastructure/llm/paragraphLlm.ts index e0ed05c..ece68ec 100644 --- a/src/modules/lecture/infrastructure/llm/paragraphLlm.ts +++ b/src/modules/lecture/infrastructure/llm/paragraphLlm.ts @@ -4,6 +4,7 @@ import type { SummaryJson } from "../../domain/types"; import type { TextChunk } from "../pdf/chunker"; import { splitSentences } from "../pdf/sentenceSplit"; import type { StoredParagraph, StoredSentence } from "../storage/lectureStore"; +import { FORCE_ZH_EXPLANATION, FORCE_ZH_USER_REMINDER } from "./promptRules"; import { requestStructuredOutput } from "./structuredOutput"; const PARA_SYSTEM = `你是 ChatPapers 论文伴读助手。用户会按论文物理顺序逐段听课。 @@ -15,7 +16,9 @@ const PARA_SYSTEM = `你是 ChatPapers 论文伴读助手。用户会按论文 - contextLink:1–2 句,说明本段与上一段及全文摘要的衔接(代词指代、逻辑转折等)。 - roleInPaper:本段在论文结构中的作用(如「方法开篇」「实验设置」)。 - sentences:将本段拆成 2–8 个朗读单元(按句号/问号/叹号分句),每项含 original(原文句)与 translation(该句的中文讲解,30–80 字)。 -- 术语与专有名词翻译前后一致;指代前文概念时用相同译法。`; +- 术语与专有名词翻译前后一致;指代前文概念时用相同译法。 + +${FORCE_ZH_EXPLANATION}`; export interface ParagraphLlmResult { translation: string; @@ -100,6 +103,8 @@ ${options.priorContext || "(这是论文开头第一段)"} 【当前段落 ${options.chunk.id}】 ${options.chunk.text} +${FORCE_ZH_USER_REMINDER} + 请输出 JSON。`; return requestStructuredOutput({ diff --git a/src/modules/lecture/infrastructure/llm/promptRules.ts b/src/modules/lecture/infrastructure/llm/promptRules.ts new file mode 100644 index 0000000..93861fe --- /dev/null +++ b/src/modules/lecture/infrastructure/llm/promptRules.ts @@ -0,0 +1,9 @@ +/** 伴读/讲解 LLM 输出须为中文,即使原文是英文论文。 */ +export const FORCE_ZH_EXPLANATION = `语言(强制): +- 无论原文是英文、中文或中英混合,JSON 内所有讲解/摘要类字段必须全部使用简体中文,严禁输出整句英文。 +- 原文为英文时:translation、script 等须先准确译成中文再口语讲解,不得直接复述、改写或总结英文原文。 +- 专有名词、缩写、符号名可保留英文,但其余讲解正文必须是中文。`; + +/** 用户消息末尾的语言提醒(原文可能是英文段落/句子)。 */ +export const FORCE_ZH_USER_REMINDER = + "【语言】无论上文原文是否为英文,JSON 中所有讲解字段必须全部使用简体中文。"; diff --git a/src/modules/lecture/infrastructure/llm/sentenceLlm.ts b/src/modules/lecture/infrastructure/llm/sentenceLlm.ts index dea2573..0eef6b4 100644 --- a/src/modules/lecture/infrastructure/llm/sentenceLlm.ts +++ b/src/modules/lecture/infrastructure/llm/sentenceLlm.ts @@ -1,6 +1,7 @@ import { parseJsonLoose } from "../../../llm/jsonParse"; import { LlmError } from "../../../llm/types"; import type { SummaryJson } from "../../domain/types"; +import { FORCE_ZH_EXPLANATION, FORCE_ZH_USER_REMINDER } from "./promptRules"; import { requestStructuredOutput } from "./structuredOutput"; const SENTENCE_SYSTEM = `你是 ChatPapers 论文伴读助手。用户选中论文中的一句原文,需要你解释并用于语音朗读。 @@ -11,7 +12,9 @@ const SENTENCE_SYSTEM = `你是 ChatPapers 论文伴读助手。用户选中论 - translation:准确中文翻译,并用 30–80 字口语解释该句含义(不要念 LaTeX,公式转述为口语)。 - syntaxNote:1–2 句,拆解句法结构或关键术语(英文句为主;中文句可简述逻辑)。 - contextRole:1 句,说明该句在段落或全文论证中的作用。 -- 术语翻译与全文保持一致。`; +- 术语翻译与全文保持一致。 + +${FORCE_ZH_EXPLANATION}`; export interface SentenceLlmResult { translation: string; @@ -67,6 +70,8 @@ ${options.surroundingContext?.trim() || "(无)"} 【用户选中的句子】 ${options.selectedText.trim()} +${FORCE_ZH_USER_REMINDER} + 请输出 JSON。`; return requestStructuredOutput({