@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/README.md +8 -3
- package/dist/babeldoc-install.js +167 -0
- package/dist/host.js +19 -0
- package/dist/tools.js +1 -1
- package/dist/transcribe.js +120 -102
- package/dist/translate.js +40 -21
- package/package.json +3 -2
- package/presets/paper-reader/agent.cordis.yml +10 -6
- package/presets/paper-reader/preset.yml +1 -1
- package/reader/index.html +17 -7
- package/reader/vendor/pdf.min.mjs +29 -0
- package/reader/vendor/pdf.worker.min.mjs +29 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ggboy123/dsh-paper-reader",
|
|
3
|
-
"version": "0.
|
|
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
|
|
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
|
|
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
|
|
33
|
-
-
|
|
34
|
-
-
|
|
35
|
-
-
|
|
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
|
|
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
|
-
|
|
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(
|
|
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
|
|
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
|
-
|
|
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);
|