dsh-plugin-litsearch 0.3.5 → 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 +89 -14
- package/client/client.js +1192 -108
- package/lib/host/events.d.ts +9 -1
- package/lib/host/events.js +50 -3
- package/lib/host/router.js +66 -1
- package/lib/host/tasks/download.d.ts +104 -0
- package/lib/host/tasks/download.js +274 -0
- package/lib/host/tasks/filter.d.ts +8 -1
- package/lib/host/tasks/filter.js +14 -0
- package/lib/host/tasks/service.d.ts +34 -3
- package/lib/host/tasks/service.js +130 -17
- package/lib/host/tools.d.ts +4 -0
- package/lib/host/tools.js +808 -9
- package/lib/host/zotero/connector.d.ts +19 -10
- package/lib/host/zotero/connector.js +142 -39
- package/lib/host/zotero/match.d.ts +27 -0
- package/lib/host/zotero/match.js +59 -0
- package/lib/search/config.d.ts +0 -2
- package/lib/search/config.js +0 -2
- package/lib/search/types.d.ts +136 -1
- package/lib/search/types.js +7 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
不用注册账号、不用申请密钥、也不用另外启动什么服务。装上以后,AI 可以直接帮你查公开学术文献;你也可以在 DSH 右侧栏用同样的数据源自己查,看到感兴趣的论文,点一下就能交给 AI 接着读。
|
|
6
6
|
|
|
7
|
-
> 当前版本 **v0.3.
|
|
7
|
+
> 当前版本 **v0.3.5**:七个免费文献来源,外加可选的谷歌学术;支持一次写多条检索式、反复调整条件重搜、自动去重、筛选与图表概览、边读边筛与分组、跨页选中与批量操作、PDF 预览下载(含开放获取补全与失败归类)、**在对话里说一句话就批量下载或批量存入 Zotero**、选目录同步、导出台账与批量加入对话。
|
|
8
8
|
>
|
|
9
9
|
> 下面的「能做什么」是写给使用者的;再往后的安装、配置、数据目录、架构等章节面向开发者和运维。
|
|
10
10
|
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
2. 结果按来源列出来,每篇能看到标题、作者、年份、被引次数,以及「能不能免费下载全文」。
|
|
19
19
|
3. 看到有用的,点「加入对话」,AI 就能基于这篇帮你总结、比较或写提纲。
|
|
20
20
|
|
|
21
|
-
也可以直接在聊天里让 AI
|
|
21
|
+
也可以直接在聊天里让 AI 去找,结果同样出现在右侧栏,你随时能接手;想批量下 PDF 也直接说一句就行(见「在对话里批量下载」)。
|
|
22
22
|
|
|
23
23
|
### 找得全,也找得准
|
|
24
24
|
|
|
@@ -41,20 +41,23 @@
|
|
|
41
41
|
- **一眼看清整批文献**:「概览」页用环形图、折线图和双色条展示一共找到多少、筛到哪一步、多少篇有全文,以及年份、来源、类型、语言、作者怎么分布;图上任意一块都能点,直接筛出对应的论文。
|
|
42
42
|
- **想筛就筛**:按关键词、来源、年份、类型、语言、有没有全文、读没读过来过滤,结果一页一页翻,篇数多也不会挤成一团。
|
|
43
43
|
- **想细看就单独打开**:每篇论文有自己的页面,完整摘要、编号、PDF 与网页版全文都集中在一处;有 PMID 的论文还能看到系统标出的基因、疾病、化学物等关键词。
|
|
44
|
-
-
|
|
44
|
+
- **全文有没有,一本账**:「全文」页按整批结果统计,列出哪些能免费下、哪些需要订阅、哪些被出版社拦了、哪些压根没有可用地址、哪些已经下载好;点数字就能看清单,再批量下载或存进 Zotero,还能把这份清单带回结果页继续筛。
|
|
45
45
|
|
|
46
46
|
### 读过的都记得住
|
|
47
47
|
|
|
48
48
|
- 每篇可以标「没读 / 读过 / 纳入 / 排除」;同一任务里还能建「研究分组」,按「为什么读」归类并导出分层报告。
|
|
49
49
|
- 换一轮检索也不会丢:标过的筛读状态会跟着论文一直保留。
|
|
50
50
|
- 可以拿当前结果和某个旧任务对比,看新增了哪些、共有哪些、少了哪些,并把「新增」一键整批标成纳入。
|
|
51
|
-
- 批量操作都在勾选后完成:批量改筛读状态、归入或移出分组、下载 PDF、存 Zotero
|
|
51
|
+
- 批量操作都在勾选后完成:批量改筛读状态、归入或移出分组、下载 PDF、存 Zotero、按选中导出。
|
|
52
|
+
- **跨页选中不丢**:排序右侧有「本页全选 / 取消全选」,本页全选是累加而非替换,翻页或改排序都保留已选文献,累计数量一直显示在工具栏上;跨页选中的文献会异步补齐标题再参与批量操作。「取消全选」清空所有页的已选。
|
|
53
|
+
- 批量下载固定 5 个并发,已下载的自动跳过,弹窗里逐篇实时显示状态;存入 Zotero 同样是 5 并发、逐篇进度。
|
|
52
54
|
|
|
53
55
|
### 全文和参考文献库都接得上
|
|
54
56
|
|
|
55
57
|
- 能免费下载的 PDF 可以直接在结果里预览,或下载到电脑(默认放在当前工作目录的 `dsh-litsearch/` 文件夹,文件名带作者、年份、标题,好认好找)。没有 PDF 但有 PMC 编号时,会给出排版好的网页版全文。
|
|
56
|
-
-
|
|
57
|
-
-
|
|
58
|
+
- 下载前会按「论文自带的 PDF 直链 → 开放获取副本 → 全文渲染页」依次尝试;**在设置页填了联系邮箱还会启用 Unpaywall**,按 DOI 补出更多开放获取地址。补出来的出版商直链仍可能被拒绝,此时会落到下面的失败归类。
|
|
59
|
+
- 批量下载把「需手动获取」和「失败」分开统计:出版商要求订阅、登录或人机验证时,后台程序拿不到 PDF(浏览器带着会话和机构授权反而能打开);403 / 限流、人机验证页、返回的其实是 HTML 登录页、压根没有 PDF 地址,都会分别给出原因,点卡片上的 PDF / DOI 链接在浏览器打开后手动另存即可。
|
|
60
|
+
- 电脑上开着 Zotero 桌面端的话,点「存入 Zotero」会先弹出目录选择框(列出 Zotero 里的目录,标明当前选中和不可写附件的目录),确认后 5 并发逐篇同步、实时显示结果,可随时取消;没连上、存了一半失败或目录只读都会明确告诉你,并保留一条只含本次条目的 RIS 导出作为备用。**也可以直接在对话框里说一句「把这批存到综述目录」**,详见下面两节。
|
|
58
61
|
- 要交给别的软件用,可以导出 CSV 表格、RIS、BibTeX 或 Markdown 报告;按当前筛选或只按勾选的条目都行。
|
|
59
62
|
|
|
60
63
|
### 和 AI 接着聊
|
|
@@ -62,6 +65,48 @@
|
|
|
62
65
|
- 点「加入对话」,论文会变成输入框里的一个小卡片(胶囊),鼠标停上去就能看到标题、出处和摘要;发送后 AI 拿到的是完整信息。一次勾多篇会合成一个卡片,按顺序编号。
|
|
63
66
|
- 整个任务也能「加入对话」,方便在新会话里明确续接同一个任务。
|
|
64
67
|
- **不会自动发送,也不会自作主张再搜一轮**:每轮结束后 AI 只给「怎么把检索改得更好」的建议,是否继续由你决定。
|
|
68
|
+
- **下载和存 Zotero 都能直接说**:在对话框说「下载当前页的所有 PDF」「把这批存到综述目录」,AI 会把范围算准并让右侧栏弹出对应的批量操作框,详见下面两节。
|
|
69
|
+
|
|
70
|
+
### 在对话里批量下载
|
|
71
|
+
|
|
72
|
+
直接在对话框说要下什么,模型会用 `literature_download` 把范围算成一份已校验的文献清单;右侧栏**自动弹出批量下载框并立即开始**,与手动勾选后点批量下载走的是同一套流程:逐篇显示标题、来源与实时状态,已下载的自动跳过,付费墙 / 需手动获取的单独归类。
|
|
73
|
+
|
|
74
|
+
| 你可以这么说 | 实际范围 |
|
|
75
|
+
| --- | --- |
|
|
76
|
+
| 「帮我下载标题带 xxx 的那篇」「下载这几篇」 | 指定文献(用结果里给出的 `paperId`) |
|
|
77
|
+
| 「帮我下载当前页的所有 pdf 文献」 | 右侧栏当前这一页,且仅有 PDF 直链或已下载 |
|
|
78
|
+
| 「把第二页有 pdf 的文献下载下来」「下载第 4–5 页」 | 面板上的第 2 页 / 第 4–5 页(每页 20 条);叠加 `hasPdf` 时先切页、再在页内筛 |
|
|
79
|
+
| 「下载『综述』分组下的文献」 | 指定分组,跨页全量 |
|
|
80
|
+
| 「下载 2023 年以后、开放获取、已纳入的文献」 | 按条件筛选 |
|
|
81
|
+
| 「帮我下载当前全部文献」 | 当前筛选下的全部结果(跨页);明确说「整个任务 / 不管筛选」才下全任务 |
|
|
82
|
+
|
|
83
|
+
- **页码由宿主换算,模型不翻页、也不搬 id**:`scope=pages` + `pages=[2]`(或 `[4,5]`)交给服务端按视图快照的排序、筛选与每页 20 条切片,再与 `hasPdf` 等条件在页内取交集。`pageBase='view'`(默认)是「第 2 页里有 PDF 的」,`pageBase='filtered'` 是「有 PDF 的文献里的第 2 页」。页码越界会直接拒绝下发并给出总页数。
|
|
84
|
+
- **不确定范围时可以先预演**:`literature_scope` 是只读工具,参数与下载 / 同步完全一致,返回命中篇数、总页数、面板当前视图与清单前 10 篇(含 `paperId` 与有无 PDF),核对无误后再执行,不会产生任何指令。
|
|
85
|
+
- 模型跑在后台,看不到界面。「当前页」「第 N 页」「当前全部」由右侧栏定期上报的视图快照 + 服务端筛选精确解析,清单里每个 `paperId` 都会与任务结果逐一校验,模型编造的 id 会被忽略。面板还没打开或快照过期时,工具会提示先打开任务页,不会按错误的基准切页。
|
|
86
|
+
- 面板每页固定 20 条(`RESULT_PAGE_SIZE`),与任务条件的「每源条数」不是一回事:模型侧按页取数只认前者,`literature_task current/get` 会直接回显「面板视图:第 1/30 页|每页 20 条|筛选…」。
|
|
87
|
+
- 弹窗顶部标明「模型发起」、范围说明与篇数,并附上你的原话;每篇显示标题、来源与期刊·年份,方便核对有没有选错。可随时点「取消下载」中止(**关闭弹窗只隐藏,后台仍会继续跑完**);取消只能中止尚未发出的请求,已到达后台的仍可能落盘,刷新任务页会同步真实状态。手动批量下载的交互保持不变。
|
|
88
|
+
- 连续说几条下载指令会**排队串行执行**,不会丢也不会重复;任务 tab 没打开时先自动拉起。
|
|
89
|
+
- `hasPdf`(有 PDF 直链或已下载)与 `openAccessOnly`(上游标记为开放获取)是两套口径,不会混用;付费墙文献不会静默算作成功。
|
|
90
|
+
- 不设单次篇数上限:几千篇会明显耗时并可能触发上游限流,已下载的会跳过、失败会归类,建议大范围下载前先收窄条件。视图快照只存内存,宿主重启后需重新打开任务页才能解析「当前页」。
|
|
91
|
+
- 该功能依赖新增的模型工具,**升级后需重启宿主或重新加载插件**才会注册生效。
|
|
92
|
+
|
|
93
|
+
### 在对话里批量存入 Zotero
|
|
94
|
+
|
|
95
|
+
`literature_zotero` 与下载工具**共用同一套范围解析**(7 种 `scope` + `ResultsQuery` 筛选字段 + 视图快照 + 逐个校验 `paperId`),同样把范围算成一份已校验清单下发给右侧栏,由右侧栏复用「存入 Zotero」弹窗逐篇执行。区别只有一步:**目录**。
|
|
96
|
+
|
|
97
|
+
| 你可以这么说 | 实际行为 |
|
|
98
|
+
| --- | --- |
|
|
99
|
+
| 「把『综述』分组的文献存到 Zotero」(没提目录) | 弹窗加载好文献和目录,**由你选目录再点「同步」**,与手动操作完全一致 |
|
|
100
|
+
| 「把这批存到『综述』目录」 | 工具先在本机 Zotero 目录列表里核实目录 → 弹窗**自动预选并立即开始同步** |
|
|
101
|
+
| 「存到『综述』」但 Zotero 里有多个匹配 / 找不到 | **不下发任何指令**,工具返回可用目录清单,让模型在对话里向你确认 |
|
|
102
|
+
| 「把当前页的文献存到 Zotero」 | 范围与「当前页」下载一致:右侧栏正在看的这一页,可叠加 `hasPdf` 等条件 |
|
|
103
|
+
|
|
104
|
+
- 目录匹配只认**唯一命中**:id 精确 → 名称精确(忽略大小写与空白)→ 名称包含;任何一步命中多个都算歧义。**绝不猜一个目录就写入数据**,因为同步会真的在 Zotero 里建条目。
|
|
105
|
+
- 弹窗顶部标明「模型发起」、范围说明、篇数与你的原话;每篇显示标题、来源与期刊·年份,以及待同步 / 同步中 / 已同步 / 失败。可随时取消(只停止派发后续文献,已发出的请求仍会完成),失败时同样保留 RIS 兜底导出。
|
|
106
|
+
- Zotero 桌面端没开、目录列表读不到、或设置里关闭了「Zotero 同步」时,工具直接返回错误**不下发指令**,也不会偷偷改存「我的文库」;指定目录只读时仍能同步条目,但不带 PDF 附件,弹窗会标明。
|
|
107
|
+
- **不跳过「已同步」文献**:模型触发沿用现有重跑语义,会在 Zotero 里新建条目、不覆盖已有条目。大范围指令前建议先收窄条件。
|
|
108
|
+
- 指令与下载链路**并列且互不干扰**:走 `/events` 的 `zotero[]` 增量(1.5s 轮询)、按 `commandId` 幂等、10 分钟窗口、任务 tab 没打开时先自动拉起;弹窗开着时后续指令排队,关闭后串行消费。手动同步的交互零变化。
|
|
109
|
+
- 同样**需重启宿主或重新加载插件**,新工具才会注册生效。
|
|
65
110
|
|
|
66
111
|
## 搜索任务与轮次
|
|
67
112
|
|
|
@@ -103,7 +148,7 @@ dsh plugin --profile <profile> add dsh-plugin-litsearch
|
|
|
103
148
|
| `defaultPageSize` | 每个来源默认取多少条 | 20 |
|
|
104
149
|
| `requestTimeoutMs` | 单次上游请求超时(毫秒);Europe PMC 检索另有 25000 下限 | 20000 |
|
|
105
150
|
| `defaultSources` / `defaultSort` / `defaultLanguage` | 新任务默认勾选的数据源、排序与语言;设置页按来源分组,可逐个开关(至少保留一个) | 七个免费源 / 相关度 / 不限 |
|
|
106
|
-
| `autoOpenTaskTab` / `maxTaskTabs` |
|
|
151
|
+
| `autoOpenTaskTab` / `maxTaskTabs` | 模型发起检索**或对话里下发批量下载 / 存入 Zotero 指令**后自动打开 / 聚焦任务 tab;每个对话只保留一个任务 tab,打开新任务会替换旧的。`maxTaskTabs` 为自动打开的兜底上限(按最近真实打开过的 tab 计数,30 分钟后释放名额) | 开 / 5 |
|
|
107
152
|
| `taskRetentionDays` / `taskRetentionCount` / `taskMaxPapers` | 未保留任务保留天数、保留条数、单任务结果上限(在任务列表中可标记「保留」跳过清理) | 90 / 120 / 1500 |
|
|
108
153
|
| `pdfRoot` / `pdfMaxMb` / `autoDownloadPdf` | PDF 保存目录、单文件上限(MB)、检索完成后自动下载;`pdfRoot` 留空时落在当前会话工作目录下的 `dsh-litsearch/` | 跟随工作目录 / 30 / 关 |
|
|
109
154
|
| `pdfCacheMaxMb` | 内部 PDF 去重缓存总量上限(MB),超出时从最旧文件开始清理;0 表示不自动清理 | 512 |
|
|
@@ -129,6 +174,7 @@ $DSH_HOME/storages/dsh-plugin-litsearch/
|
|
|
129
174
|
- `DSH_HOME` 由宿主注入,未设置时回落 `~/.dsh`;设置页「存储目录」展示当前实际生效的路径。
|
|
130
175
|
- 旧版本的数据写在 `~/.dsh/dsh-litsearch/`。首次启动时若新目录为空而旧目录有任务,会把任务、导出文件与缓存**复制**到新目录并重建索引,**旧目录原样保留作备份**;新目录已有任务时不再迁移,复制失败则暂时回退到旧目录读取,不会丢筛读状态。
|
|
131
176
|
- **PDF 可读文件不在这里**:它由 `pdfRoot` 决定;未显式配置时落在当前会话工作目录下的 `dsh-litsearch/`(读不到工作目录时才回落到旧默认 `~/Downloads/dsh-litsearch`)。任务里记录的 `pdfFile` 是该目录下的绝对路径,升级不影响已下载的文件;只有内部去重缓存 `pdfs/` 随任务目录一起搬迁。
|
|
177
|
+
- **视图快照与下载指令不落盘**:「当前页 / 当前筛选」快照(30 分钟过期)和模型下发的下载指令(10 分钟窗口)只留在宿主内存里,不写进上面的目录,也不外发;宿主重启后归零。
|
|
132
178
|
|
|
133
179
|
## Zotero 同步
|
|
134
180
|
|
|
@@ -136,16 +182,18 @@ $DSH_HOME/storages/dsh-plugin-litsearch/
|
|
|
136
182
|
|
|
137
183
|
1. 启动 Zotero 桌面端,保持运行;
|
|
138
184
|
2. 在「设置 → 高级」中允许其他应用与本机通信(若该版本提供此开关);
|
|
139
|
-
3.
|
|
185
|
+
3. 勾选文献(或单篇卡片)点「存入 Zotero」,弹窗里**先选目标目录**再点「同步」。目录列表直接来自本机 Zotero,会标出「当前选中」和「不可写附件」的目录,不必事先在 Zotero 里选中分类;没有可写目录时会提示先在 Zotero 中新建分类。
|
|
140
186
|
|
|
141
|
-
|
|
187
|
+
同步以 5 并发逐篇进行,弹窗实时显示每篇的待同步 / 同步中 / 已同步 / 失败,可随时取消(已发出的请求仍会完成)。写入条目元数据、分组名(作为标签)与可选 PDF 附件;连接失败、目录不可写附件、单篇条目或附件失败都会给出具体原因,目录只读时只保存条目、不尝试上传 PDF。重新同步会在 Zotero 里新建条目,**不会覆盖已有条目**,也不会跳过已同步的文献。同步失败或部分失败时,任务页会保留一条 RIS 导出入口(只含本次同步的条目),可先导出备用。
|
|
188
|
+
|
|
189
|
+
在对话里说一句也能触发同样的同步,且支持在话术里直接点名目录(点名且唯一匹配时自动预选并开跑);详见「在对话里批量存入 Zotero」。目录名称的匹配在插件后台完成,不需要先在 Zotero 里选中分类。
|
|
142
190
|
|
|
143
191
|
## 隐私
|
|
144
192
|
|
|
145
193
|
- 检索词会发送给所选数据源(PubMed、Europe PMC、OpenAlex、Crossref、Semantic Scholar、arXiv、PubTator)的公开 API。
|
|
146
194
|
- 配置了 `contactEmail` 后,下载 PDF 会用 DOI 和该邮箱查询 Unpaywall(`api.unpaywall.org`)以寻找开放获取副本;不配置则不发这项请求。
|
|
147
195
|
- 启用「谷歌学术」时,检索词会经第三方服务 SerpAPI 转发,并受其使用条款与额度约束;该来源默认关闭。
|
|
148
|
-
- PDF 下载与 Zotero 连接都只在本机进行;Zotero connector
|
|
196
|
+
- PDF 下载与 Zotero 连接都只在本机进行;Zotero connector 仅允许回环地址。右侧栏的视图快照与模型下载 / 同步指令也只在宿主内存里传递,不落盘、不上传。
|
|
149
197
|
- 各类 API Key(含 `serpApiKey`)只保存在本机配置文件(明文)中,界面不回显、不写日志。
|
|
150
198
|
|
|
151
199
|
## 本地开发
|
|
@@ -158,6 +206,8 @@ pnpm typecheck:client
|
|
|
158
206
|
pnpm test # node:test 单元测试(test/**/*.test.ts)
|
|
159
207
|
```
|
|
160
208
|
|
|
209
|
+
下载 / Zotero 指令链路另有专项单测:`test/download-scope.test.ts`(范围解析、无效 id 过滤、当前页顺序、按页切分与页内再筛、页码越界)、`download-events.test.ts`(事件增量与裁剪 / 重置)、`download-store.test.ts`(指令幂等与会话隔离)、`zotero-command.test.ts`(目录匹配歧义、指令幂等、事件增量)。
|
|
210
|
+
|
|
161
211
|
构建后用独立的本地 profile 启动调试:
|
|
162
212
|
|
|
163
213
|
```bash
|
|
@@ -171,11 +221,31 @@ dsh --profile litsearch
|
|
|
171
221
|
|
|
172
222
|
- `src/search/`:数据源无关的检索层(类型、聚合、身份合并、查询适配、限流、健康状态)。
|
|
173
223
|
- `src/search/providers/`:每家 API 一个 provider,新增数据源只需实现 `Provider` 并注册;其中 `googlescholar` 为需自备密钥的可选源。
|
|
174
|
-
- `src/host/`:`/dsh-litsearch/api/*` 端点、任务执行 / 持久化 / 统计 /
|
|
224
|
+
- `src/host/`:`/dsh-litsearch/api/*` 端点、任务执行 / 持久化 / 统计 / 导出,以及七个模型工具(`literature_search` / `literature_sources` / `literature_task` / `literature_scope` / `literature_export` / `literature_download` / `literature_zotero`)的注册。
|
|
225
|
+
- `src/host/tasks/download.ts`:把模型的自然语言范围(7 种 `scope`,含按页取数的 `pages` + 复用 `ResultsQuery` 的筛选字段)解析成已校验的 paperId 清单与中文范围说明;复用 `filterPapers`,不自造筛选 DSL。下载与 Zotero 两个工具共用 `tools.ts` 里的 `resolveModelScope()`,不会出现两套筛选口径。
|
|
175
226
|
- `src/host/paths.ts`:`$DSH_HOME` 解析、统一存储区路径、旧目录一次性迁移与失败回退。
|
|
176
|
-
- `src/host/pdf/`:PDF 候选链、SSRF 防护的抓取与本地缓存、可读文件名、Europe PMC
|
|
177
|
-
- `src/host/zotero/`:本机 Zotero connector
|
|
178
|
-
- `src/client/`:右侧栏检索面板、任务 tab(结果 / 概览 / 分组 / 笔记 / 对比 / 全文)、独立论文 tab
|
|
227
|
+
- `src/host/pdf/`:PDF 候选链、SSRF 防护的抓取与本地缓存、可读文件名、Europe PMC 全文兜底、下载失败原因归类。
|
|
228
|
+
- `src/host/zotero/`:本机 Zotero connector 协议封装(探测、目录列表、保存条目、上传附件),以及 `match.ts`(把对话里点名的目录唯一匹配到真实目标,歧义返回候选)。
|
|
229
|
+
- `src/client/`:右侧栏检索面板、任务 tab(结果 / 概览 / 分组 / 笔记 / 对比 / 全文)、独立论文 tab 与设置页;`DownloadDialog.tsx` 是批量下载进度弹窗,`ZoteroSyncDialog.tsx` 是选目录 + 逐篇同步弹窗(模型发起时支持预选目录并自动开跑)。
|
|
230
|
+
- `src/client/downloadCommandStore.ts` / `zoteroCommandStore.ts`:两类模型指令各自的幂等去重与待消费队列(按 `commandId`,10 分钟窗口),彼此独立、互不覆盖。
|
|
231
|
+
|
|
232
|
+
### 模型 → 右侧栏的指令链路
|
|
233
|
+
|
|
234
|
+
Host 没有原生推送,两侧靠 `/events` 增量轮询联动:
|
|
235
|
+
|
|
236
|
+
```text
|
|
237
|
+
右侧栏 POST /view(400ms 节流上报当前页 / 筛选 / 选中)
|
|
238
|
+
→ Host 按 sessionId 存内存 Map(30 分钟过期)
|
|
239
|
+
→ 模型调 literature_download / literature_zotero:读快照 + 服务端筛选算出 paperId 清单
|
|
240
|
+
(Zotero 额外读本机目录列表,点名了目录就唯一匹配,歧义/找不到一律不下发)
|
|
241
|
+
→ publishDownload / publishZotero 写入各自日志并推进 rev(各最多保留 50 条)
|
|
242
|
+
→ 右侧栏 GET /events?sinceRev=…(1.5s 轮询)拿到 downloads[] / zotero[]
|
|
243
|
+
→ downloadCommandStore / zoteroCommandStore 按 commandId 去重、排队
|
|
244
|
+
→ TaskPane 消费 → startBatchDownload(5 并发)→ DownloadDialog
|
|
245
|
+
→ ZoteroSyncDialog(选目录;已指定目录则自动开跑)
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
两个工具都同时 `focusTask` 拉起任务 tab;tab 没挂载时指令在 store 里等待,不会丢失。快照、指令、事件日志都在内存里,宿主重启后归零,不重放历史指令。
|
|
179
249
|
|
|
180
250
|
## 路线图
|
|
181
251
|
|
|
@@ -193,6 +263,11 @@ dsh --profile litsearch
|
|
|
193
263
|
- [x] 对比视图整批纳入、Zotero 失败回退 RIS
|
|
194
264
|
- [x] Unpaywall(按 DOI 补全开放获取全文地址;需配置 `contactEmail`)
|
|
195
265
|
- [x] 谷歌学术(可选源,需自备 SerpAPI Key)与设置页数据源开关
|
|
266
|
+
- [x] 批量下载进度弹窗、跨页选中累加、下载与 Zotero 同步 5 并发
|
|
267
|
+
- [x] PDF 候选补全与失败归类(403 / 限流 / 人机验证 / HTML 页 / 无候选)
|
|
268
|
+
- [x] Zotero 同步前选择目标目录与逐篇结果
|
|
269
|
+
- [x] 对话里自然语言触发批量下载(视图快照 + 已校验 paperId 清单)
|
|
270
|
+
- [x] 对话里自然语言触发批量存入 Zotero(共用范围解析 + 目录唯一匹配 + 自动开跑)
|
|
196
271
|
- [ ] DOAJ
|
|
197
272
|
|
|
198
273
|
## License
|