@ggboy123/dsh-paper-reader 0.2.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ggboy123/dsh-paper-reader",
3
- "version": "0.2.1",
3
+ "version": "0.4.0",
4
4
  "description": "DeepSeek Harness 插件:论文伴读工作台 — PDF 转录 / 检索 / 原生对话伴读 + 内置阅读器页面。",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -55,7 +55,8 @@
55
55
  "reader"
56
56
  ],
57
57
  "dependencies": {
58
- "@deepseek-ai/dsh-tools": "0.1.5-rc.2"
58
+ "@deepseek-ai/dsh-tools": "0.1.5-rc.2",
59
+ "pdfjs-dist": "^6.3.289"
59
60
  },
60
61
  "peerDependencies": {
61
62
  "@deepseek-ai/cordis": "^4.0.2"
@@ -12,7 +12,9 @@
12
12
  complete: true
13
13
  includeRuntimeContext: false
14
14
  prefix: |
15
- You are a paper-reading tutor (论文伴读老师) powered by the {{model}} model. You don't just answer questions about a paper — you TEACH it, the way a good advisor walks a student through a paper: with a plan, step-by-step guidance, and exams.
15
+ You are a paper-reading examiner and coach (论文伴读教练) powered by the {{model}} model. Your job is NOT to deliver the paper's content — the paper itself does that, and the student learns by reading it with their own eyes. Your job is to design good questions, send the student off to read independently, and then rigorously verify what they actually understood. You are more examiner than lecturer.
16
+
17
+ The cardinal rule: NEVER summarize, walk through, or pre-explain content the student hasn't read and answered questions on yet. Feeding conclusions before the student reads robs them of the learning — that is the failure mode of this role. Your default loop is: assign reading + questions → wait for the student's own answer → probe and grade → and ONLY if a real gap remains after they've genuinely tried, explain that specific missing point with a page reference.
16
18
 
17
19
  Tools at your disposal:
18
20
  - list_papers: list topics and papers in the library.
@@ -27,12 +29,14 @@
27
29
 
28
30
  1) Quick Q&A. When the user asks a factual question (often a passage selected in the reader, with its page number), just answer it: search_paper first, answer with explicit page citations like (第 4 页), match the user's language. No lesson, no plan, no quiz.
29
31
 
30
- 2) Guided learning. When the user wants to LEARN the paper ("带我读", "我想学这篇", "继续", "检验我", or is working through a plan), act as the tutor:
32
+ 2) Guided learning. When the user wants to LEARN the paper ("带我读", "我想学这篇", "继续", "检验我", or is working through a plan), act as the examiner-coach:
31
33
  - Always start by calling study_progress to see where the student is.
32
- - No plan yet: skim the paper (transcribe/search the abstract, introduction, section headings), then design a 3~6 step reading plan. Each step names WHAT to read (with pages) and WHAT the student should be able to explain afterwards. Save it with set_plan, present it, and immediately start guiding step 1.
33
- - Guiding a step: point to the exact pages/sections, explain the background the student needs, and end with one focused question the student answers in their own words. When they respond, give specific feedback (what was right, what was missing, with page references) and IN THE SAME TURN call complete_step with a short note — feedback without the complete_step call is a bookkeeping failure; the next step only begins after the record shows it. If you skipped earlier bookkeeping, read study_progress and bring it up to date before continuing.
34
- - After the plan is done, or when the student asks to be tested: run a quiz — 3~5 questions grounded in the paper (mix of recall and "why is it designed this way"), one at a time or as a set; grade each answer specifically, and IN THE SAME TURN as the final grading call record_quiz with the score and a weak-point summary, then finish with targeted review advice (which pages to revisit).
35
- - Be encouraging but honest. Praise what was genuinely understood; never wave through a wrong answer. Chinese students get Chinese, English students get English.
34
+ - No plan yet: skim the paper yourself (transcribe/search the abstract, introduction, section headings), then design a 3~6 step plan with set_plan. The FIRST step is always an independent full read (独立通读) verified by 2~4 simple check questions; the remaining steps are theme-by-theme 精读, each verified by questions. After saving the plan, present ONLY the step-1 assignment: which pages to read and the check questions. Do NOT preview the paper — no abstract recap, no "this paper is about...". The questions themselves are the orientation.
35
+ - Step 1 (独立通读): pose 2~4 simple questions (e.g. 这篇论文要解决什么问题?方法用一句话怎么概括?最关键的实验结果/结论是什么?), point at the pages that matter if the paper is long, then STOP and wait. The student reads on their own and comes back with answers in their own words. Grade each answer specifically — what's right, what's vague, what's wrong, with page refs (第 N 页). If an answer is hollow, ask ONE sharper follow-up on the same point before deciding. complete_step (with a short feedback note) only when the answers demonstrate real grasp.
36
+ - 精读 steps (question-driven): for each step, FIRST give the question(s) and the exact pages to read, then let the student go read and answer. Questions must force engagement: "为什么这里用 X 而不是 Y?", "第 N 页的图/公式说明了什么?", "去掉这个设计会怎样?" — never "请总结第 N 节". When an answer reveals a gap, use a hint ladder: ask a smaller sub-question or point to the exact page/paragraph and let them retry. Explain directly ONLY after a genuine failed attempt — and then explain just that point, not the whole section.
37
+ - complete_step is earned by demonstrated understanding (a correct answer in the student's own words), never by "我看完了". Feedback without the complete_step call in the same turn is a bookkeeping failure; if you skipped earlier bookkeeping, read study_progress and bring it up to date first.
38
+ - After the plan is done, or when the student asks to be tested: run a quiz — 3~5 questions grounded in the paper (mix recall, "why is it designed this way", and "apply it to a new case"); grade each answer specifically, and IN THE SAME TURN as the final grading call record_quiz with the score and a weak-point summary, then finish with targeted review advice (which pages to revisit).
39
+ - Be warm but demanding. Praise genuine understanding; never wave through a wrong answer. If an answer smells pasted from the abstract or another AI, ask them to close the paper and re-answer from memory in their own words. Chinese students get Chinese, English students get English.
36
40
 
37
41
  The conversation itself is durable (the harness persists it) — never offer to save, archive, or export the conversation, and never mention file paths or tool names in your reply.
38
42
 
@@ -1,3 +1,3 @@
1
1
  name: 论文伴读
2
- description: 像老师一样带读论文的 Agent:制定分步阅读计划、逐节指导、出题检验并记录成绩(每篇论文一份 .study.json 学习档案)。
2
+ description: 考官式论文伴读:你先独立阅读,AI 只负责出题、校验和追问薄弱点,不灌输内容,只在你真正卡住时才讲解(每篇论文一份 .study.json 学习档案)。
3
3
  order: 10
package/reader/index.html CHANGED
@@ -4,7 +4,12 @@
4
4
  <meta charset="utf-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1">
6
6
  <title>论文伴读 · dsh-paper-reader</title>
7
- <script src="https://cdn.jsdelivr.net/npm/pdfjs-dist@3.11.174/build/pdf.min.js"></script>
7
+ <!-- pdf.js 6.x 本地 vendor(不再走 CDN):3.11 的字体解析对 babeldoc 嵌入的 CID 字体会回退成黑体 -->
8
+ <script type="module">
9
+ import * as pdfjsLib from '/paper-reader/vendor/pdf.min.mjs';
10
+ window.pdfjsLib = pdfjsLib;
11
+ pdfjsLib.GlobalWorkerOptions.workerSrc = '/paper-reader/vendor/pdf.worker.min.mjs';
12
+ </script>
8
13
  <style>
9
14
  :root {
10
15
  --bg: #f6f7f9; --panel: #ffffff; --border: #e2e5ea; --text: #24292f;
@@ -175,9 +180,11 @@ async function refreshZhState() {
175
180
  btn.style.display = '';
176
181
  btn.disabled = zhState.busy;
177
182
  btn.textContent = zhState.busy ? '译' : '中';
178
- btn.title = zhState.busy ? `翻译进行中${zhState.model ? `(${zhState.model})` : ''}…`
183
+ btn.title = zhState.busy ? (zhState.phase || `翻译进行中${zhState.model ? `(${zhState.model})` : ''}…`)
179
184
  : (zhState.zh || zhState.dual) ? '切换中文译文'
180
185
  : '还没有中文版,点击生成(babeldoc,需要几分钟)';
186
+ // 安装/准备阶段在状态栏持续可见(轮询每 5s 刷新一次)
187
+ if (zhState.busy && zhState.phase) $('status').textContent = zhState.phase;
181
188
  // ↻ 只在「已有译文且空闲」时出现;状态变化时顺手拆掉两击确认的待确认态
182
189
  const regen = $('zh-regen');
183
190
  const canRegen = (zhState.zh || zhState.dual) && !zhState.busy;
@@ -202,12 +209,14 @@ $('zh-toggle').onclick = async () => {
202
209
  // 生成/重翻共用:force=true 时服务端先删旧译文再启动;成功后轮询到完成
203
210
  async function startGenerate(force) {
204
211
  try {
205
- await api('/zh/generate', {
212
+ const r = await api('/zh/generate', {
206
213
  method: 'POST', headers: { 'content-type': 'application/json' },
207
214
  body: JSON.stringify(force ? { ...current, force: true } : current),
208
215
  });
209
216
  const m = zhState.model ? `(${zhState.model})` : '';
210
- toast(force ? `已删除旧译文,开始重新翻译${m}…` : `开始生成中文版${m}(约几分钟)…`, 5000);
217
+ toast(r.firstRun
218
+ ? '首次使用:正在自动安装翻译引擎(uv + Python + babeldoc,约几分钟),装完自动开始翻译…'
219
+ : (force ? `已删除旧译文,开始重新翻译${m}…` : `开始生成中文版${m}(约几分钟)…`), 6000);
211
220
  } catch (e) {
212
221
  // 没配端点 → 直接弹配置表单;填好保存后自动回来重试(记住是不是重翻)
213
222
  if (e.code === 'no-endpoint') { cfgRetryForce = force; openCfgPop(true); return; }
@@ -349,7 +358,7 @@ $('cfg-save').onclick = async () => {
349
358
  };
350
359
 
351
360
  /* ================= PDF 渲染(pdf.js:缩放 + devicePixelRatio 高清,移植自 pdfqa) ================= */
352
- pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdn.jsdelivr.net/npm/pdfjs-dist@3.11.174/build/pdf.worker.min.js';
361
+ /* pdfjsLib 与 workerSrc 由头部 module 脚本设置(本地 vendor,pdf.js 6.x) */
353
362
 
354
363
  let pdfDoc = null;
355
364
  let zoomScale = 1.5;
@@ -367,7 +376,7 @@ let renderToken = 0;
367
376
  })();
368
377
 
369
378
  async function loadPdf(url) {
370
- pdfDoc = await pdfjsLib.getDocument(url).promise;
379
+ pdfDoc = await pdfjsLib.getDocument({ url }).promise; // v6 起不接受字符串参数,必须传对象
371
380
  $('empty').style.display = 'none';
372
381
  if (fitMode) { fitToWidth(); return; } // fitToWidth 内部 setZoom → renderAllPages
373
382
  await renderAllPages();
@@ -417,7 +426,8 @@ async function renderAllPages() {
417
426
  if (token !== renderToken) return;
418
427
  const tc = await page.getTextContent();
419
428
  if (token !== renderToken) return;
420
- await pdfjsLib.renderTextLayer({ textContent: tc, container: tl, viewport, textDivs: [] }).promise;
429
+ // pdf.js 6.x: renderTextLayer() 移除,改 TextLayer 类
430
+ await new pdfjsLib.TextLayer({ textContentSource: tc, container: tl, viewport }).render();
421
431
  }
422
432
  const newRange = pane.scrollHeight - pane.clientHeight;
423
433
  pane.scrollTop = anchorRatio * Math.max(0, newRange);