ai4scholar 0.1.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/LICENSE +21 -0
- package/README.md +159 -0
- package/assets/styles.css +588 -0
- package/assets/template_fulltext.html +342 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +65 -0
- package/dist/index.js.map +1 -0
- package/dist/src/commands.d.ts +5 -0
- package/dist/src/commands.d.ts.map +1 -0
- package/dist/src/commands.js +89 -0
- package/dist/src/commands.js.map +1 -0
- package/dist/src/hooks/scholar-mode.d.ts +16 -0
- package/dist/src/hooks/scholar-mode.d.ts.map +1 -0
- package/dist/src/hooks/scholar-mode.js +10 -0
- package/dist/src/hooks/scholar-mode.js.map +1 -0
- package/dist/src/tools/api-client.d.ts +19 -0
- package/dist/src/tools/api-client.d.ts.map +1 -0
- package/dist/src/tools/api-client.js +119 -0
- package/dist/src/tools/api-client.js.map +1 -0
- package/dist/src/tools/arxiv.d.ts +20 -0
- package/dist/src/tools/arxiv.d.ts.map +1 -0
- package/dist/src/tools/arxiv.js +83 -0
- package/dist/src/tools/arxiv.js.map +1 -0
- package/dist/src/tools/biorxiv.d.ts +37 -0
- package/dist/src/tools/biorxiv.d.ts.map +1 -0
- package/dist/src/tools/biorxiv.js +76 -0
- package/dist/src/tools/biorxiv.js.map +1 -0
- package/dist/src/tools/google-scholar.d.ts +20 -0
- package/dist/src/tools/google-scholar.d.ts.map +1 -0
- package/dist/src/tools/google-scholar.js +57 -0
- package/dist/src/tools/google-scholar.js.map +1 -0
- package/dist/src/tools/params.d.ts +8 -0
- package/dist/src/tools/params.d.ts.map +1 -0
- package/dist/src/tools/params.js +35 -0
- package/dist/src/tools/params.js.map +1 -0
- package/dist/src/tools/pubmed.d.ts +71 -0
- package/dist/src/tools/pubmed.d.ts.map +1 -0
- package/dist/src/tools/pubmed.js +118 -0
- package/dist/src/tools/pubmed.js.map +1 -0
- package/dist/src/tools/result.d.ts +19 -0
- package/dist/src/tools/result.d.ts.map +1 -0
- package/dist/src/tools/result.js +21 -0
- package/dist/src/tools/result.js.map +1 -0
- package/dist/src/tools/semantic-scholar.d.ts +159 -0
- package/dist/src/tools/semantic-scholar.d.ts.map +1 -0
- package/dist/src/tools/semantic-scholar.js +254 -0
- package/dist/src/tools/semantic-scholar.js.map +1 -0
- package/openclaw.plugin.json +34 -0
- package/package.json +60 -0
- package/scripts/__pycache__/fulltext_search.cpython-313.pyc +0 -0
- package/scripts/__pycache__/generate_html.cpython-313.pyc +0 -0
- package/scripts/__pycache__/translate_titles.cpython-313.pyc +0 -0
- package/scripts/fulltext_search.py +386 -0
- package/scripts/generate_html.py +632 -0
- package/scripts/translate_titles.py +156 -0
- package/skills/literature-survey/SKILL.md +206 -0
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>全文搜索报告 - {{QUERY}}</title>
|
|
7
|
+
<style>
|
|
8
|
+
{{STYLES}}
|
|
9
|
+
</style>
|
|
10
|
+
</head>
|
|
11
|
+
<body>
|
|
12
|
+
|
|
13
|
+
<script>
|
|
14
|
+
const SEARCH_QUERY = "{{QUERY}}";
|
|
15
|
+
const SEARCH_TERMS = SEARCH_QUERY.toLowerCase().split(/\s+/).filter(t => t.length > 2);
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<!-- 主题切换器 -->
|
|
19
|
+
<div class="theme-switcher">
|
|
20
|
+
<button class="theme-toggle" title="切换主题">
|
|
21
|
+
<svg id="themeIcon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
22
|
+
<circle cx="12" cy="12" r="4"/>
|
|
23
|
+
<path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M6.34 17.66l-1.41 1.41M19.07 4.93l-1.41 1.41"/>
|
|
24
|
+
</svg>
|
|
25
|
+
</button>
|
|
26
|
+
<div class="theme-panel">
|
|
27
|
+
<button class="theme-btn active" data-theme="light" title="明亮"></button>
|
|
28
|
+
<button class="theme-btn" data-theme="sepia" title="护眼"></button>
|
|
29
|
+
<button class="theme-btn" data-theme="dark" title="深色"></button>
|
|
30
|
+
<button class="theme-btn" data-theme="green" title="自然"></button>
|
|
31
|
+
<button class="theme-btn" data-theme="pink" title="浪漫"></button>
|
|
32
|
+
<button class="theme-btn" data-theme="perplexity" title="Perplexity"></button>
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
|
|
36
|
+
<div class="container">
|
|
37
|
+
|
|
38
|
+
<!-- 报告头部 -->
|
|
39
|
+
<header class="report-header">
|
|
40
|
+
<div class="header-top">
|
|
41
|
+
<div class="header-brand">
|
|
42
|
+
<a href="https://ai4scholar.net" target="_blank" class="brand-name">AI4Scholar</a>
|
|
43
|
+
</div>
|
|
44
|
+
<div class="header-links">
|
|
45
|
+
<span class="header-text">OpenClaw Plugin</span>
|
|
46
|
+
<span class="header-divider">·</span>
|
|
47
|
+
<a href="https://github.com/literaf/ai4scholar" target="_blank">GitHub</a>
|
|
48
|
+
</div>
|
|
49
|
+
</div>
|
|
50
|
+
<h1 class="report-title">全文搜索报告</h1>
|
|
51
|
+
<p class="report-subtitle">基于 Semantic Scholar 数据库,覆盖 2 亿+ 学术论文</p>
|
|
52
|
+
</header>
|
|
53
|
+
|
|
54
|
+
<!-- 搜索参数卡片 -->
|
|
55
|
+
{{SEARCH_PARAMS_CARD}}
|
|
56
|
+
|
|
57
|
+
<!-- 搜索概况 -->
|
|
58
|
+
<div class="section-header">
|
|
59
|
+
<div class="section-icon">
|
|
60
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
61
|
+
<path d="M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z"/>
|
|
62
|
+
<polyline points="14 2 14 8 20 8"/>
|
|
63
|
+
</svg>
|
|
64
|
+
</div>
|
|
65
|
+
<div>
|
|
66
|
+
<h2 class="section-title">搜索概况</h2>
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
|
|
70
|
+
<div class="summary-card">
|
|
71
|
+
<div class="summary-content">{{SUMMARY}}</div>
|
|
72
|
+
</div>
|
|
73
|
+
|
|
74
|
+
<!-- 匹配片段列表 -->
|
|
75
|
+
<div class="section-header">
|
|
76
|
+
<div class="section-icon">
|
|
77
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
78
|
+
<path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"/>
|
|
79
|
+
<path d="M14 2v4a2 2 0 0 0 2 2h4"/>
|
|
80
|
+
</svg>
|
|
81
|
+
</div>
|
|
82
|
+
<div>
|
|
83
|
+
<h2 class="section-title">匹配片段</h2>
|
|
84
|
+
<p class="section-subtitle">按相关度排序</p>
|
|
85
|
+
</div>
|
|
86
|
+
</div>
|
|
87
|
+
|
|
88
|
+
<!-- 筛选栏 -->
|
|
89
|
+
<div class="filter-bar">
|
|
90
|
+
<div class="filter-group">
|
|
91
|
+
<label>排序</label>
|
|
92
|
+
<select id="sortFilter">
|
|
93
|
+
<option value="relevance">默认(相关度)</option>
|
|
94
|
+
<option value="date-desc">日期(新→旧)</option>
|
|
95
|
+
<option value="date-asc">日期(旧→新)</option>
|
|
96
|
+
</select>
|
|
97
|
+
</div>
|
|
98
|
+
<div class="filter-group">
|
|
99
|
+
<label>来源类型</label>
|
|
100
|
+
<div class="filter-buttons" id="kindFilter">
|
|
101
|
+
<button class="filter-btn active" data-value="">全部</button>
|
|
102
|
+
<button class="filter-btn" data-value="title">标题</button>
|
|
103
|
+
<button class="filter-btn" data-value="abstract">摘要</button>
|
|
104
|
+
<button class="filter-btn" data-value="body">正文</button>
|
|
105
|
+
</div>
|
|
106
|
+
</div>
|
|
107
|
+
<div class="filter-group">
|
|
108
|
+
<label>年份</label>
|
|
109
|
+
<select id="yearFilter">
|
|
110
|
+
{{FILTER_YEARS}}
|
|
111
|
+
</select>
|
|
112
|
+
</div>
|
|
113
|
+
<div class="filter-group">
|
|
114
|
+
<label>期刊</label>
|
|
115
|
+
<select id="venueFilter">
|
|
116
|
+
{{FILTER_VENUES}}
|
|
117
|
+
</select>
|
|
118
|
+
</div>
|
|
119
|
+
<div class="filter-group search-group">
|
|
120
|
+
<input type="text" id="textSearch" placeholder="搜索...">
|
|
121
|
+
</div>
|
|
122
|
+
<div class="filter-stats">
|
|
123
|
+
<span id="visibleCount">0</span>/<span id="totalCount">0</span>
|
|
124
|
+
</div>
|
|
125
|
+
</div>
|
|
126
|
+
|
|
127
|
+
<div class="snippets-grid" id="snippetsGrid">
|
|
128
|
+
{{SNIPPET_CARDS}}
|
|
129
|
+
</div>
|
|
130
|
+
|
|
131
|
+
<!-- 片段详情弹窗 -->
|
|
132
|
+
{{MODALS}}
|
|
133
|
+
|
|
134
|
+
<footer id="footer">
|
|
135
|
+
<p class="footer-main">由 <a href="https://ai4scholar.net" target="_blank">AI4Scholar</a> · OpenClaw 生成 · {{DATETIME}}</p>
|
|
136
|
+
<p class="footer-desc">数据来源:Semantic Scholar · Allen Institute for AI</p>
|
|
137
|
+
<div class="footer-links">
|
|
138
|
+
<a href="https://ai4scholar.net" target="_blank">AI4Scholar</a>
|
|
139
|
+
<span class="sep">·</span>
|
|
140
|
+
<a href="https://github.com/literaf/ai4scholar" target="_blank">GitHub</a>
|
|
141
|
+
</div>
|
|
142
|
+
</footer>
|
|
143
|
+
|
|
144
|
+
</div>
|
|
145
|
+
|
|
146
|
+
<!-- 主题切换脚本 -->
|
|
147
|
+
<script>
|
|
148
|
+
const themeIcons = {
|
|
149
|
+
light: '<circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M6.34 17.66l-1.41 1.41M19.07 4.93l-1.41 1.41"/>',
|
|
150
|
+
sepia: '<path d="M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7Z"/><circle cx="12" cy="12" r="3"/>',
|
|
151
|
+
dark: '<path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"/>',
|
|
152
|
+
green: '<path d="M7 20h10"/><path d="M10 20c5.5-2.5.8-6.4 3-10"/><path d="M9.5 9.4c1.1.8 1.8 2.2 2.3 3.7-2 .4-3.5.4-4.8-.3-1.2-.6-2.3-1.9-3-4.2 2.8-.5 4.4 0 5.5.8Z"/><path d="M14.1 6a7 7 0 0 0-1.1 4c1.9-.1 3.3-.6 4.3-1.4 1-1 1.6-2.3 1.7-4.6-2.7.1-4 1-4.9 2Z"/>',
|
|
153
|
+
pink: '<path d="M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.3 1.5 4.05 3 5.5l7 7Z"/>',
|
|
154
|
+
perplexity: '<polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/>'
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
function setTheme(theme) {
|
|
158
|
+
document.documentElement.setAttribute('data-theme', theme === 'light' ? '' : theme);
|
|
159
|
+
localStorage.setItem('ai4s-theme', theme);
|
|
160
|
+
document.getElementById('themeIcon').innerHTML = themeIcons[theme];
|
|
161
|
+
document.querySelectorAll('.theme-btn').forEach(btn => {
|
|
162
|
+
btn.classList.toggle('active', btn.dataset.theme === theme);
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
document.querySelectorAll('.theme-btn').forEach(btn => {
|
|
167
|
+
btn.addEventListener('click', () => setTheme(btn.dataset.theme));
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
(function() {
|
|
171
|
+
const saved = localStorage.getItem('ai4s-theme') || 'light';
|
|
172
|
+
setTheme(saved);
|
|
173
|
+
})();
|
|
174
|
+
</script>
|
|
175
|
+
|
|
176
|
+
<!-- 高亮脚本 -->
|
|
177
|
+
<script>
|
|
178
|
+
function highlightText(el) {
|
|
179
|
+
if (!SEARCH_TERMS.length) return;
|
|
180
|
+
let html = el.innerHTML;
|
|
181
|
+
SEARCH_TERMS.forEach(t => {
|
|
182
|
+
html = html.replace(new RegExp(`(${t})`, 'gi'), '<mark>$1</mark>');
|
|
183
|
+
});
|
|
184
|
+
el.innerHTML = html;
|
|
185
|
+
}
|
|
186
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
187
|
+
document.querySelectorAll('[data-highlight]').forEach(highlightText);
|
|
188
|
+
});
|
|
189
|
+
</script>
|
|
190
|
+
|
|
191
|
+
<!-- 弹窗脚本 -->
|
|
192
|
+
<script>
|
|
193
|
+
function openModal(id) { document.getElementById(id).classList.add('show'); }
|
|
194
|
+
function closeModal(id) { document.getElementById(id).classList.remove('show'); }
|
|
195
|
+
window.onclick = e => { if (e.target.classList.contains('modal')) e.target.classList.remove('show'); };
|
|
196
|
+
document.addEventListener('keydown', e => {
|
|
197
|
+
if (e.key === 'Escape') document.querySelectorAll('.modal').forEach(m => m.classList.remove('show'));
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
function copyText(id, btn) {
|
|
201
|
+
const text = document.getElementById(id).innerText;
|
|
202
|
+
|
|
203
|
+
function showSuccess() {
|
|
204
|
+
btn.style.background = '#dcfce7';
|
|
205
|
+
btn.style.color = '#22c55e';
|
|
206
|
+
btn.innerHTML = '✓ 已复制';
|
|
207
|
+
setTimeout(() => {
|
|
208
|
+
btn.style.background = '';
|
|
209
|
+
btn.style.color = '';
|
|
210
|
+
btn.innerHTML = '复制';
|
|
211
|
+
}, 1500);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function fallbackCopy(text) {
|
|
215
|
+
const textArea = document.createElement('textarea');
|
|
216
|
+
textArea.value = text;
|
|
217
|
+
textArea.style.position = 'fixed';
|
|
218
|
+
textArea.style.left = '-9999px';
|
|
219
|
+
textArea.style.top = '-9999px';
|
|
220
|
+
document.body.appendChild(textArea);
|
|
221
|
+
textArea.focus();
|
|
222
|
+
textArea.select();
|
|
223
|
+
try {
|
|
224
|
+
const success = document.execCommand('copy');
|
|
225
|
+
if (success) {
|
|
226
|
+
showSuccess();
|
|
227
|
+
} else {
|
|
228
|
+
alert('复制失败,请手动复制');
|
|
229
|
+
}
|
|
230
|
+
} catch (err) {
|
|
231
|
+
console.error('复制失败:', err);
|
|
232
|
+
alert('复制失败,请手动复制');
|
|
233
|
+
} finally {
|
|
234
|
+
document.body.removeChild(textArea);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
if (navigator.clipboard && window.isSecureContext) {
|
|
239
|
+
navigator.clipboard.writeText(text).then(showSuccess).catch(() => fallbackCopy(text));
|
|
240
|
+
} else {
|
|
241
|
+
fallbackCopy(text);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
</script>
|
|
245
|
+
|
|
246
|
+
<!-- 筛选脚本 -->
|
|
247
|
+
<script>
|
|
248
|
+
(function() {
|
|
249
|
+
const grid = document.getElementById('snippetsGrid');
|
|
250
|
+
const cards = grid ? Array.from(grid.querySelectorAll('.snippet-card')) : [];
|
|
251
|
+
const visibleEl = document.getElementById('visibleCount');
|
|
252
|
+
const totalEl = document.getElementById('totalCount');
|
|
253
|
+
|
|
254
|
+
// 保存原始顺序
|
|
255
|
+
const originalOrder = cards.map((card, index) => ({ card, index }));
|
|
256
|
+
|
|
257
|
+
if (totalEl) totalEl.textContent = cards.length;
|
|
258
|
+
if (visibleEl) visibleEl.textContent = cards.length;
|
|
259
|
+
|
|
260
|
+
let filters = { kind: '', year: '', venue: '', text: '', sort: 'relevance' };
|
|
261
|
+
|
|
262
|
+
function sortCards() {
|
|
263
|
+
let sorted = [...originalOrder];
|
|
264
|
+
|
|
265
|
+
if (filters.sort === 'date-desc') {
|
|
266
|
+
sorted.sort((a, b) => {
|
|
267
|
+
const yearA = parseInt(a.card.dataset.year) || 0;
|
|
268
|
+
const yearB = parseInt(b.card.dataset.year) || 0;
|
|
269
|
+
return yearB - yearA;
|
|
270
|
+
});
|
|
271
|
+
} else if (filters.sort === 'date-asc') {
|
|
272
|
+
sorted.sort((a, b) => {
|
|
273
|
+
const yearA = parseInt(a.card.dataset.year) || 0;
|
|
274
|
+
const yearB = parseInt(b.card.dataset.year) || 0;
|
|
275
|
+
return yearA - yearB;
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
// relevance 保持原始顺序
|
|
279
|
+
|
|
280
|
+
// 重新排列 DOM 并更新编号
|
|
281
|
+
sorted.forEach((item, idx) => {
|
|
282
|
+
grid.appendChild(item.card);
|
|
283
|
+
// 更新卡片编号
|
|
284
|
+
const numEl = item.card.querySelector('.snippet-num');
|
|
285
|
+
if (numEl) numEl.textContent = `[${idx + 1}]`;
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function apply() {
|
|
290
|
+
let count = 0;
|
|
291
|
+
cards.forEach(c => {
|
|
292
|
+
const match =
|
|
293
|
+
(!filters.kind || c.dataset.kind === filters.kind) &&
|
|
294
|
+
(!filters.year || c.dataset.year === filters.year) &&
|
|
295
|
+
(!filters.venue || c.dataset.venue === filters.venue) &&
|
|
296
|
+
(!filters.text || (c.dataset.title + c.dataset.text).toLowerCase().includes(filters.text.toLowerCase()));
|
|
297
|
+
c.style.display = match ? '' : 'none';
|
|
298
|
+
if (match) count++;
|
|
299
|
+
});
|
|
300
|
+
if (visibleEl) visibleEl.textContent = count;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// 排序选择
|
|
304
|
+
document.getElementById('sortFilter')?.addEventListener('change', function() {
|
|
305
|
+
filters.sort = this.value;
|
|
306
|
+
sortCards();
|
|
307
|
+
apply();
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
// 按钮筛选
|
|
311
|
+
document.querySelectorAll('#kindFilter .filter-btn').forEach(btn => {
|
|
312
|
+
btn.addEventListener('click', function() {
|
|
313
|
+
document.querySelectorAll('#kindFilter .filter-btn').forEach(b => b.classList.remove('active'));
|
|
314
|
+
this.classList.add('active');
|
|
315
|
+
filters.kind = this.dataset.value;
|
|
316
|
+
apply();
|
|
317
|
+
});
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
document.getElementById('yearFilter')?.addEventListener('change', function() {
|
|
321
|
+
filters.year = this.value;
|
|
322
|
+
apply();
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
document.getElementById('venueFilter')?.addEventListener('change', function() {
|
|
326
|
+
filters.venue = this.value;
|
|
327
|
+
apply();
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
let timer;
|
|
331
|
+
document.getElementById('textSearch')?.addEventListener('input', function() {
|
|
332
|
+
clearTimeout(timer);
|
|
333
|
+
timer = setTimeout(() => {
|
|
334
|
+
filters.text = this.value;
|
|
335
|
+
apply();
|
|
336
|
+
}, 200);
|
|
337
|
+
});
|
|
338
|
+
})();
|
|
339
|
+
</script>
|
|
340
|
+
|
|
341
|
+
</body>
|
|
342
|
+
</html>
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AA6BlD,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,GAAG,EAAE,iBAAiB,QAqEtD"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { setApiKey } from "./src/tools/api-client.js";
|
|
2
|
+
import { createSemanticSearchTool, createSemanticDetailTool, createSemanticCitationsTool, createSemanticReferencesTool, createSemanticAuthorSearchTool, createSemanticAuthorPapersTool, createSemanticRecommendationsTool, createSemanticRecommendationsForPaperTool, createSemanticSnippetSearchTool, } from "./src/tools/semantic-scholar.js";
|
|
3
|
+
import { createPubmedSearchTool, createPubmedDetailTool, createPubmedCitationsTool, createPubmedRelatedTool, } from "./src/tools/pubmed.js";
|
|
4
|
+
import { createGoogleScholarSearchTool } from "./src/tools/google-scholar.js";
|
|
5
|
+
import { createArxivSearchTool } from "./src/tools/arxiv.js";
|
|
6
|
+
import { createBiorxivSearchTool, createMedrxivSearchTool } from "./src/tools/biorxiv.js";
|
|
7
|
+
import { handleLibrary, handleProjects, handleReadingList, } from "./src/commands.js";
|
|
8
|
+
import { createScholarModeHook } from "./src/hooks/scholar-mode.js";
|
|
9
|
+
export default function register(api) {
|
|
10
|
+
const cfg = api.pluginConfig;
|
|
11
|
+
if (cfg?.apiKey) {
|
|
12
|
+
setApiKey(cfg.apiKey);
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
api.logger.warn("AI4Scholar: no apiKey configured. Semantic Scholar, PubMed, and Google Scholar tools require an API key from ai4scholar.net.");
|
|
16
|
+
}
|
|
17
|
+
// --- Semantic Scholar (9 tools) ---
|
|
18
|
+
api.registerTool(createSemanticSearchTool());
|
|
19
|
+
api.registerTool(createSemanticDetailTool());
|
|
20
|
+
api.registerTool(createSemanticCitationsTool());
|
|
21
|
+
api.registerTool(createSemanticReferencesTool());
|
|
22
|
+
api.registerTool(createSemanticAuthorSearchTool());
|
|
23
|
+
api.registerTool(createSemanticAuthorPapersTool());
|
|
24
|
+
api.registerTool(createSemanticRecommendationsTool());
|
|
25
|
+
api.registerTool(createSemanticRecommendationsForPaperTool());
|
|
26
|
+
api.registerTool(createSemanticSnippetSearchTool());
|
|
27
|
+
// --- PubMed (4 tools) ---
|
|
28
|
+
api.registerTool(createPubmedSearchTool());
|
|
29
|
+
api.registerTool(createPubmedDetailTool());
|
|
30
|
+
api.registerTool(createPubmedCitationsTool());
|
|
31
|
+
api.registerTool(createPubmedRelatedTool());
|
|
32
|
+
// --- Google Scholar (1 tool) ---
|
|
33
|
+
api.registerTool(createGoogleScholarSearchTool());
|
|
34
|
+
// --- arXiv (1 tool) ---
|
|
35
|
+
api.registerTool(createArxivSearchTool());
|
|
36
|
+
// --- bioRxiv & medRxiv (2 tools) ---
|
|
37
|
+
api.registerTool(createBiorxivSearchTool());
|
|
38
|
+
api.registerTool(createMedrxivSearchTool());
|
|
39
|
+
// --- Slash commands ---
|
|
40
|
+
api.registerCommand({
|
|
41
|
+
name: "library",
|
|
42
|
+
description: "List downloaded papers in the active project",
|
|
43
|
+
acceptsArgs: false,
|
|
44
|
+
requireAuth: false,
|
|
45
|
+
handler: handleLibrary,
|
|
46
|
+
});
|
|
47
|
+
api.registerCommand({
|
|
48
|
+
name: "projects",
|
|
49
|
+
description: "List all literature projects",
|
|
50
|
+
acceptsArgs: false,
|
|
51
|
+
requireAuth: false,
|
|
52
|
+
handler: handleProjects,
|
|
53
|
+
});
|
|
54
|
+
api.registerCommand({
|
|
55
|
+
name: "reading-list",
|
|
56
|
+
description: "Show the reading list for the active project",
|
|
57
|
+
acceptsArgs: false,
|
|
58
|
+
requireAuth: false,
|
|
59
|
+
handler: handleReadingList,
|
|
60
|
+
});
|
|
61
|
+
// --- Scholar mode hook ---
|
|
62
|
+
api.on("before_prompt_build", createScholarModeHook(), { priority: 100 });
|
|
63
|
+
api.logger.info(`AI4Scholar plugin loaded — 17 tools registered (apiKey: ${cfg?.apiKey ? "configured" : "missing"})`);
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { PluginCommandContext, PluginCommandResult } from "openclaw";
|
|
2
|
+
export declare function handleLibrary(_ctx: PluginCommandContext): PluginCommandResult;
|
|
3
|
+
export declare function handleProjects(_ctx: PluginCommandContext): PluginCommandResult;
|
|
4
|
+
export declare function handleReadingList(_ctx: PluginCommandContext): PluginCommandResult;
|
|
5
|
+
//# sourceMappingURL=commands.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/commands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAwB1E,wBAAgB,aAAa,CAC3B,IAAI,EAAE,oBAAoB,GACzB,mBAAmB,CAiCrB;AAED,wBAAgB,cAAc,CAC5B,IAAI,EAAE,oBAAoB,GACzB,mBAAmB,CAoBrB;AAED,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,oBAAoB,GACzB,mBAAmB,CA0BrB"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
const WORKSPACE_BASE = path.join(process.env.HOME ?? "~", ".openclaw", "workspace", "projects");
|
|
4
|
+
function getActiveProject() {
|
|
5
|
+
const activeFile = path.join(WORKSPACE_BASE, ".active");
|
|
6
|
+
if (!fs.existsSync(activeFile))
|
|
7
|
+
return null;
|
|
8
|
+
return fs.readFileSync(activeFile, "utf-8").trim() || null;
|
|
9
|
+
}
|
|
10
|
+
function getProjectDir(projectId) {
|
|
11
|
+
const id = projectId ?? getActiveProject();
|
|
12
|
+
if (!id)
|
|
13
|
+
return null;
|
|
14
|
+
const dir = path.join(WORKSPACE_BASE, id);
|
|
15
|
+
return fs.existsSync(dir) ? dir : null;
|
|
16
|
+
}
|
|
17
|
+
export function handleLibrary(_ctx) {
|
|
18
|
+
const projectDir = getProjectDir();
|
|
19
|
+
if (!projectDir) {
|
|
20
|
+
return { text: "No active project. Start a literature search first." };
|
|
21
|
+
}
|
|
22
|
+
const papersDir = path.join(projectDir, "papers", "_meta");
|
|
23
|
+
if (!fs.existsSync(papersDir)) {
|
|
24
|
+
return { text: "No papers downloaded yet." };
|
|
25
|
+
}
|
|
26
|
+
const metaFiles = fs.readdirSync(papersDir).filter((f) => f.endsWith(".json"));
|
|
27
|
+
if (metaFiles.length === 0) {
|
|
28
|
+
return { text: "Paper library is empty." };
|
|
29
|
+
}
|
|
30
|
+
const lines = [`**Paper Library** (${metaFiles.length} papers)\n`];
|
|
31
|
+
for (const file of metaFiles.slice(0, 20)) {
|
|
32
|
+
try {
|
|
33
|
+
const meta = JSON.parse(fs.readFileSync(path.join(papersDir, file), "utf-8"));
|
|
34
|
+
const title = meta.title ?? "Untitled";
|
|
35
|
+
const id = meta.arxiv_id ?? meta.pmid ?? meta.paper_id ?? file.replace(".json", "");
|
|
36
|
+
lines.push(`- **${title}** (${id})`);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
lines.push(`- ${file.replace(".json", "")}`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (metaFiles.length > 20) {
|
|
43
|
+
lines.push(`\n... and ${metaFiles.length - 20} more.`);
|
|
44
|
+
}
|
|
45
|
+
return { markdown: lines.join("\n") };
|
|
46
|
+
}
|
|
47
|
+
export function handleProjects(_ctx) {
|
|
48
|
+
if (!fs.existsSync(WORKSPACE_BASE)) {
|
|
49
|
+
return { text: "No projects found. Start a literature search to create one." };
|
|
50
|
+
}
|
|
51
|
+
const active = getActiveProject();
|
|
52
|
+
const entries = fs.readdirSync(WORKSPACE_BASE, { withFileTypes: true });
|
|
53
|
+
const projects = entries.filter((e) => e.isDirectory());
|
|
54
|
+
if (projects.length === 0) {
|
|
55
|
+
return { text: "No projects found." };
|
|
56
|
+
}
|
|
57
|
+
const lines = ["**Projects**\n"];
|
|
58
|
+
for (const p of projects) {
|
|
59
|
+
const marker = p.name === active ? " ← active" : "";
|
|
60
|
+
lines.push(`- ${p.name}${marker}`);
|
|
61
|
+
}
|
|
62
|
+
return { markdown: lines.join("\n") };
|
|
63
|
+
}
|
|
64
|
+
export function handleReadingList(_ctx) {
|
|
65
|
+
const projectDir = getProjectDir();
|
|
66
|
+
if (!projectDir) {
|
|
67
|
+
return { text: "No active project." };
|
|
68
|
+
}
|
|
69
|
+
const readingListFile = path.join(projectDir, "reading-list.json");
|
|
70
|
+
if (!fs.existsSync(readingListFile)) {
|
|
71
|
+
return { text: "Reading list is empty. Ask the agent to build one for you." };
|
|
72
|
+
}
|
|
73
|
+
try {
|
|
74
|
+
const list = JSON.parse(fs.readFileSync(readingListFile, "utf-8"));
|
|
75
|
+
if (!Array.isArray(list) || list.length === 0) {
|
|
76
|
+
return { text: "Reading list is empty." };
|
|
77
|
+
}
|
|
78
|
+
const lines = [`**Reading List** (${list.length} papers)\n`];
|
|
79
|
+
for (const item of list) {
|
|
80
|
+
const status = item.read ? "✅" : "📖";
|
|
81
|
+
lines.push(`- ${status} **${item.title ?? "Untitled"}**`);
|
|
82
|
+
}
|
|
83
|
+
return { markdown: lines.join("\n") };
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
return { text: "Failed to read reading list." };
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=commands.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commands.js","sourceRoot":"","sources":["../../src/commands.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAC9B,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,GAAG,EACvB,WAAW,EACX,WAAW,EACX,UAAU,CACX,CAAC;AAEF,SAAS,gBAAgB;IACvB,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,SAAS,CAAC,CAAC;IACxD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,OAAO,IAAI,CAAC;IAC5C,OAAO,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,IAAI,IAAI,CAAC;AAC7D,CAAC;AAED,SAAS,aAAa,CAAC,SAAkB;IACvC,MAAM,EAAE,GAAG,SAAS,IAAI,gBAAgB,EAAE,CAAC;IAC3C,IAAI,CAAC,EAAE;QAAE,OAAO,IAAI,CAAC;IACrB,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;IAC1C,OAAO,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,aAAa,CAC3B,IAA0B;IAE1B,MAAM,UAAU,GAAG,aAAa,EAAE,CAAC;IACnC,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO,EAAE,IAAI,EAAE,qDAAqD,EAAE,CAAC;IACzE,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC3D,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC9B,OAAO,EAAE,IAAI,EAAE,2BAA2B,EAAE,CAAC;IAC/C,CAAC;IAED,MAAM,SAAS,GAAG,EAAE,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;IAC/E,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3B,OAAO,EAAE,IAAI,EAAE,yBAAyB,EAAE,CAAC;IAC7C,CAAC;IAED,MAAM,KAAK,GAAG,CAAC,sBAAsB,SAAS,CAAC,MAAM,YAAY,CAAC,CAAC;IACnE,KAAK,MAAM,IAAI,IAAI,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;QAC1C,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;YAC9E,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,UAAU,CAAC;YACvC,MAAM,EAAE,GAAG,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YACpF,KAAK,CAAC,IAAI,CAAC,OAAO,KAAK,OAAO,EAAE,GAAG,CAAC,CAAC;QACvC,CAAC;QAAC,MAAM,CAAC;YACP,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC;IAED,IAAI,SAAS,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;QAC1B,KAAK,CAAC,IAAI,CAAC,aAAa,SAAS,CAAC,MAAM,GAAG,EAAE,QAAQ,CAAC,CAAC;IACzD,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,cAAc,CAC5B,IAA0B;IAE1B,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;QACnC,OAAO,EAAE,IAAI,EAAE,6DAA6D,EAAE,CAAC;IACjF,CAAC;IAED,MAAM,MAAM,GAAG,gBAAgB,EAAE,CAAC;IAClC,MAAM,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,cAAc,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IACxE,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;IAExD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,EAAE,IAAI,EAAE,oBAAoB,EAAE,CAAC;IACxC,CAAC;IAED,MAAM,KAAK,GAAG,CAAC,gBAAgB,CAAC,CAAC;IACjC,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC;QACpD,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,GAAG,MAAM,EAAE,CAAC,CAAC;IACrC,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,IAA0B;IAE1B,MAAM,UAAU,GAAG,aAAa,EAAE,CAAC;IACnC,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO,EAAE,IAAI,EAAE,oBAAoB,EAAE,CAAC;IACxC,CAAC;IAED,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,mBAAmB,CAAC,CAAC;IACnE,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;QACpC,OAAO,EAAE,IAAI,EAAE,4DAA4D,EAAE,CAAC;IAChF,CAAC;IAED,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC,CAAC;QACnE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC9C,OAAO,EAAE,IAAI,EAAE,wBAAwB,EAAE,CAAC;QAC5C,CAAC;QAED,MAAM,KAAK,GAAG,CAAC,qBAAqB,IAAI,CAAC,MAAM,YAAY,CAAC,CAAC;QAC7D,KAAK,MAAM,IAAI,IAAI,IAAI,EAAE,CAAC;YACxB,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;YACtC,KAAK,CAAC,IAAI,CAAC,KAAK,MAAM,MAAM,IAAI,CAAC,KAAK,IAAI,UAAU,IAAI,CAAC,CAAC;QAC5D,CAAC;QACD,OAAO,EAAE,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,IAAI,EAAE,8BAA8B,EAAE,CAAC;IAClD,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
type HookEvent = {
|
|
2
|
+
prompt: string;
|
|
3
|
+
messages?: unknown[];
|
|
4
|
+
};
|
|
5
|
+
type HookContext = {
|
|
6
|
+
agentId?: string;
|
|
7
|
+
sessionKey?: string;
|
|
8
|
+
workspaceDir?: string;
|
|
9
|
+
};
|
|
10
|
+
type HookResult = {
|
|
11
|
+
prependContext?: string;
|
|
12
|
+
systemPrompt?: string;
|
|
13
|
+
};
|
|
14
|
+
export declare function createScholarModeHook(): (event: HookEvent, _context: HookContext) => HookResult;
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=scholar-mode.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scholar-mode.d.ts","sourceRoot":"","sources":["../../../src/hooks/scholar-mode.ts"],"names":[],"mappings":"AAAA,KAAK,SAAS,GAAG;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC;CACtB,CAAC;AAEF,KAAK,WAAW,GAAG;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,KAAK,UAAU,GAAG;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAIF,wBAAgB,qBAAqB,KAC3B,OAAO,SAAS,EAAE,UAAU,WAAW,KAAG,UAAU,CAM7D"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const SCHOLAR_MODE_PROMPT = `[AI4Scholar] For academic literature tasks (paper search, literature review, citation analysis, reading list management), match a skill from <available_skills> and read its SKILL.md before acting. Literature projects are managed under $W/projects/<topic>/. You have access to tools from ai4scholar-mcp covering Semantic Scholar, PubMed, Google Scholar, arXiv, bioRxiv, and medRxiv.`;
|
|
2
|
+
export function createScholarModeHook() {
|
|
3
|
+
return (event, _context) => {
|
|
4
|
+
if (!event.messages || event.messages.length === 0) {
|
|
5
|
+
return { prependContext: SCHOLAR_MODE_PROMPT };
|
|
6
|
+
}
|
|
7
|
+
return {};
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=scholar-mode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scholar-mode.js","sourceRoot":"","sources":["../../../src/hooks/scholar-mode.ts"],"names":[],"mappings":"AAgBA,MAAM,mBAAmB,GAAG,+XAA+X,CAAC;AAE5Z,MAAM,UAAU,qBAAqB;IACnC,OAAO,CAAC,KAAgB,EAAE,QAAqB,EAAc,EAAE;QAC7D,IAAI,CAAC,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACnD,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,CAAC;QACjD,CAAC;QACD,OAAO,EAAE,CAAC;IACZ,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare function setApiKey(key: string | undefined): void;
|
|
2
|
+
export declare function getApiKey(): string | undefined;
|
|
3
|
+
export type ApiOk<T> = {
|
|
4
|
+
ok: true;
|
|
5
|
+
data: T;
|
|
6
|
+
};
|
|
7
|
+
export type ApiErr = {
|
|
8
|
+
ok: false;
|
|
9
|
+
error: string;
|
|
10
|
+
status: number;
|
|
11
|
+
};
|
|
12
|
+
export type ApiResult<T> = ApiOk<T> | ApiErr;
|
|
13
|
+
export declare function apiGet<T = unknown>(path: string, params?: Record<string, string | number | undefined>): Promise<ApiResult<T>>;
|
|
14
|
+
export declare function apiPost<T = unknown>(path: string, body: Record<string, unknown>, params?: Record<string, string | number | undefined>): Promise<ApiResult<T>>;
|
|
15
|
+
/** Fetch raw text (e.g. arXiv Atom XML). No auth, no retry. */
|
|
16
|
+
export declare function fetchRaw(url: string): Promise<ApiResult<string>>;
|
|
17
|
+
/** Fetch JSON from a direct (non-ai4scholar) API. No auth, no retry. */
|
|
18
|
+
export declare function fetchJson<T = unknown>(url: string): Promise<ApiResult<T>>;
|
|
19
|
+
//# sourceMappingURL=api-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-client.d.ts","sourceRoot":"","sources":["../../../src/tools/api-client.ts"],"names":[],"mappings":"AAMA,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,QAEhD;AAED,wBAAgB,SAAS,IAAI,MAAM,GAAG,SAAS,CAE9C;AAED,MAAM,MAAM,KAAK,CAAC,CAAC,IAAI;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,CAAC,CAAA;CAAE,CAAC;AAC7C,MAAM,MAAM,MAAM,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAClE,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC;AAa7C,wBAAsB,MAAM,CAAC,CAAC,GAAG,OAAO,EACtC,IAAI,EAAE,MAAM,EACZ,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC,GACnD,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CA6BvB;AAED,wBAAsB,OAAO,CAAC,CAAC,GAAG,OAAO,EACvC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC,GACnD,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CA+BvB;AAED,+DAA+D;AAC/D,wBAAsB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAWtE;AAED,wEAAwE;AACxE,wBAAsB,SAAS,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAW/E"}
|