@mantra-ai/core 0.1.6 → 0.3.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/dist/discovery/ranking.d.ts +31 -0
- package/dist/discovery/ranking.d.ts.map +1 -0
- package/dist/discovery/ranking.js +214 -0
- package/dist/discovery/ranking.js.map +1 -0
- package/dist/discovery/registry.d.ts +32 -0
- package/dist/discovery/registry.d.ts.map +1 -0
- package/dist/discovery/registry.js +90 -0
- package/dist/discovery/registry.js.map +1 -0
- package/dist/discovery/types.d.ts +103 -0
- package/dist/discovery/types.d.ts.map +1 -0
- package/dist/discovery/types.js +8 -0
- package/dist/discovery/types.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/sources/semantic-scholar/citation-graph-provider.d.ts +19 -0
- package/dist/sources/semantic-scholar/citation-graph-provider.d.ts.map +1 -0
- package/dist/sources/semantic-scholar/citation-graph-provider.js +91 -0
- package/dist/sources/semantic-scholar/citation-graph-provider.js.map +1 -0
- package/dist/sources/semantic-scholar/client.d.ts +97 -0
- package/dist/sources/semantic-scholar/client.d.ts.map +1 -0
- package/dist/sources/semantic-scholar/client.js +195 -0
- package/dist/sources/semantic-scholar/client.js.map +1 -0
- package/dist/sources/semantic-scholar/provider.d.ts +22 -0
- package/dist/sources/semantic-scholar/provider.d.ts.map +1 -0
- package/dist/sources/semantic-scholar/provider.js +63 -0
- package/dist/sources/semantic-scholar/provider.js.map +1 -0
- package/dist/types/version.d.ts +84 -84
- package/dist/types/work.d.ts +216 -216
- package/package.json +1 -1
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Semantic Scholar citation-graph discovery provider.
|
|
3
|
+
*
|
|
4
|
+
* Expands from a set of seed DOIs by fetching their references (bibliography)
|
|
5
|
+
* and citations (downstream work), then returns deduplicated candidates.
|
|
6
|
+
*/
|
|
7
|
+
import { getPaperReferences, getPaperCitations, } from "./client";
|
|
8
|
+
import { s2PaperToCandidate } from "./provider";
|
|
9
|
+
/** Max concurrent seed expansions to avoid rate-limit bursts. */
|
|
10
|
+
const MAX_CONCURRENCY = 3;
|
|
11
|
+
/** Max results per direction per seed. */
|
|
12
|
+
const PER_SEED_LIMIT = 50;
|
|
13
|
+
export class SemanticScholarCitationGraphProvider {
|
|
14
|
+
name = "Semantic Scholar Citation Graph";
|
|
15
|
+
sourceKind = "semantic-scholar-citation-graph";
|
|
16
|
+
capabilities = ["search"];
|
|
17
|
+
isLocal = false;
|
|
18
|
+
clientOpts;
|
|
19
|
+
seedDois;
|
|
20
|
+
constructor(seedDois, clientOpts) {
|
|
21
|
+
this.seedDois = seedDois;
|
|
22
|
+
this.clientOpts = clientOpts ?? {};
|
|
23
|
+
}
|
|
24
|
+
async search(_query, opts) {
|
|
25
|
+
if (this.seedDois.length === 0)
|
|
26
|
+
return [];
|
|
27
|
+
const limit = opts?.limit ?? 20;
|
|
28
|
+
// Fan out across seeds with bounded concurrency, tagging each result
|
|
29
|
+
const allTagged = [];
|
|
30
|
+
const seedDoiSet = new Set(this.seedDois.map((d) => d.toLowerCase()));
|
|
31
|
+
for (let i = 0; i < this.seedDois.length; i += MAX_CONCURRENCY) {
|
|
32
|
+
const batch = this.seedDois.slice(i, i + MAX_CONCURRENCY);
|
|
33
|
+
// Build tagged request pairs: [refs-doi1, cites-doi1, refs-doi2, ...]
|
|
34
|
+
const requests = [];
|
|
35
|
+
for (const doi of batch) {
|
|
36
|
+
requests.push({
|
|
37
|
+
doi,
|
|
38
|
+
relation: "references",
|
|
39
|
+
promise: getPaperReferences(`DOI:${doi}`, { ...this.clientOpts, limit: PER_SEED_LIMIT }),
|
|
40
|
+
});
|
|
41
|
+
requests.push({
|
|
42
|
+
doi,
|
|
43
|
+
relation: "cited-by",
|
|
44
|
+
promise: getPaperCitations(`DOI:${doi}`, { ...this.clientOpts, limit: PER_SEED_LIMIT }),
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
const results = await Promise.allSettled(requests.map((r) => r.promise));
|
|
48
|
+
for (let j = 0; j < results.length; j++) {
|
|
49
|
+
const result = results[j];
|
|
50
|
+
const req = requests[j];
|
|
51
|
+
if (result.status === "fulfilled" && result.value.ok) {
|
|
52
|
+
for (const paper of result.value.data) {
|
|
53
|
+
allTagged.push({ paper, seedDoi: req.doi, relation: req.relation });
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
// Deduplicate by S2 paperId, collecting seed origins per paper
|
|
59
|
+
const paperMap = new Map();
|
|
60
|
+
for (const { paper, seedDoi, relation } of allTagged) {
|
|
61
|
+
// Exclude seed papers from results
|
|
62
|
+
const paperDoi = paper.externalIds?.DOI?.toLowerCase();
|
|
63
|
+
if (paperDoi && seedDoiSet.has(paperDoi))
|
|
64
|
+
continue;
|
|
65
|
+
const existing = paperMap.get(paper.paperId);
|
|
66
|
+
if (existing) {
|
|
67
|
+
// Add this origin if not already tracked
|
|
68
|
+
const originKey = `${seedDoi.toLowerCase()}:${relation}`;
|
|
69
|
+
if (!existing.origins.some((o) => `${o.doi.toLowerCase()}:${o.relation}` === originKey)) {
|
|
70
|
+
existing.origins.push({ doi: seedDoi, relation });
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
paperMap.set(paper.paperId, {
|
|
75
|
+
paper,
|
|
76
|
+
origins: [{ doi: seedDoi, relation }],
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// Map to candidates, scored by position (will be re-ranked by core)
|
|
81
|
+
const entries = [...paperMap.values()].slice(0, limit);
|
|
82
|
+
const candidates = entries.map(({ paper, origins }, i) => {
|
|
83
|
+
const c = s2PaperToCandidate(paper, i);
|
|
84
|
+
c.sources = ["semantic-scholar-citation-graph"];
|
|
85
|
+
c.seedOrigins = origins;
|
|
86
|
+
return c;
|
|
87
|
+
});
|
|
88
|
+
return candidates;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=citation-graph-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"citation-graph-provider.js","sourceRoot":"","sources":["../../../src/sources/semantic-scholar/citation-graph-provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed client for the Semantic Scholar Academic Graph API.
|
|
3
|
+
*
|
|
4
|
+
* Unauthenticated: 100 requests per 5 minutes.
|
|
5
|
+
* Authenticated (x-api-key header): higher limits.
|
|
6
|
+
*
|
|
7
|
+
* @see https://api.semanticscholar.org/api-docs/graph
|
|
8
|
+
*/
|
|
9
|
+
import type { AdapterResult } from "../../works/types";
|
|
10
|
+
export interface S2Author {
|
|
11
|
+
authorId: string | null;
|
|
12
|
+
name: string | null;
|
|
13
|
+
}
|
|
14
|
+
export interface S2ExternalIds {
|
|
15
|
+
DOI?: string | null;
|
|
16
|
+
ArXiv?: string | null;
|
|
17
|
+
PubMed?: string | null;
|
|
18
|
+
PMCID?: string | null;
|
|
19
|
+
MAG?: string | null;
|
|
20
|
+
CorpusId?: number | null;
|
|
21
|
+
}
|
|
22
|
+
export interface S2Paper {
|
|
23
|
+
paperId: string;
|
|
24
|
+
title: string | null;
|
|
25
|
+
abstract: string | null;
|
|
26
|
+
year: number | null;
|
|
27
|
+
authors: S2Author[];
|
|
28
|
+
citationCount: number | null;
|
|
29
|
+
influentialCitationCount: number | null;
|
|
30
|
+
venue: string | null;
|
|
31
|
+
externalIds: S2ExternalIds | null;
|
|
32
|
+
url: string | null;
|
|
33
|
+
referenceCount?: number | null;
|
|
34
|
+
isOpenAccess?: boolean | null;
|
|
35
|
+
openAccessPdf?: {
|
|
36
|
+
url: string;
|
|
37
|
+
} | null;
|
|
38
|
+
publicationDate?: string | null;
|
|
39
|
+
journal?: {
|
|
40
|
+
name: string | null;
|
|
41
|
+
} | null;
|
|
42
|
+
}
|
|
43
|
+
export interface S2SearchResponse {
|
|
44
|
+
total: number;
|
|
45
|
+
offset: number;
|
|
46
|
+
next?: number;
|
|
47
|
+
data: S2Paper[];
|
|
48
|
+
}
|
|
49
|
+
/** A single edge in a citation graph response. */
|
|
50
|
+
export interface S2CitationEdge {
|
|
51
|
+
citingPaper?: S2Paper;
|
|
52
|
+
citedPaper?: S2Paper;
|
|
53
|
+
}
|
|
54
|
+
export interface S2CitationResponse {
|
|
55
|
+
offset: number;
|
|
56
|
+
next?: number;
|
|
57
|
+
data: S2CitationEdge[];
|
|
58
|
+
}
|
|
59
|
+
export interface S2ClientOpts {
|
|
60
|
+
apiKey?: string;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Search for papers by keyword query.
|
|
64
|
+
*
|
|
65
|
+
* @see https://api.semanticscholar.org/api-docs/graph#tag/Paper-Data/operation/post_graph_get_papers_search
|
|
66
|
+
*/
|
|
67
|
+
export declare function searchPapers(query: string, opts?: S2ClientOpts & {
|
|
68
|
+
limit?: number;
|
|
69
|
+
offset?: number;
|
|
70
|
+
}): Promise<AdapterResult<S2SearchResponse>>;
|
|
71
|
+
/**
|
|
72
|
+
* Get detailed information about a single paper.
|
|
73
|
+
*
|
|
74
|
+
* Accepts S2 paper ID, DOI (prefixed with "DOI:"), ArXiv ID ("ARXIV:"), etc.
|
|
75
|
+
*
|
|
76
|
+
* @see https://api.semanticscholar.org/api-docs/graph#tag/Paper-Data/operation/post_graph_get_paper
|
|
77
|
+
*/
|
|
78
|
+
export declare function getPaperDetails(paperId: string, opts?: S2ClientOpts): Promise<AdapterResult<S2Paper>>;
|
|
79
|
+
/**
|
|
80
|
+
* Get papers referenced by a given paper (its bibliography).
|
|
81
|
+
*
|
|
82
|
+
* Returns up to `limit` cited papers.
|
|
83
|
+
* @see https://api.semanticscholar.org/api-docs/graph#tag/Paper-Data/operation/get_graph_get_paper_references
|
|
84
|
+
*/
|
|
85
|
+
export declare function getPaperReferences(paperId: string, opts?: S2ClientOpts & {
|
|
86
|
+
limit?: number;
|
|
87
|
+
}): Promise<AdapterResult<S2Paper[]>>;
|
|
88
|
+
/**
|
|
89
|
+
* Get papers that cite a given paper.
|
|
90
|
+
*
|
|
91
|
+
* Returns up to `limit` citing papers.
|
|
92
|
+
* @see https://api.semanticscholar.org/api-docs/graph#tag/Paper-Data/operation/get_graph_get_paper_citations
|
|
93
|
+
*/
|
|
94
|
+
export declare function getPaperCitations(paperId: string, opts?: S2ClientOpts & {
|
|
95
|
+
limit?: number;
|
|
96
|
+
}): Promise<AdapterResult<S2Paper[]>>;
|
|
97
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/sources/semantic-scholar/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed client for the Semantic Scholar Academic Graph API.
|
|
3
|
+
*
|
|
4
|
+
* Unauthenticated: 100 requests per 5 minutes.
|
|
5
|
+
* Authenticated (x-api-key header): higher limits.
|
|
6
|
+
*
|
|
7
|
+
* @see https://api.semanticscholar.org/api-docs/graph
|
|
8
|
+
*/
|
|
9
|
+
const BASE_URL = "https://api.semanticscholar.org/graph/v1";
|
|
10
|
+
const SEARCH_FIELDS = [
|
|
11
|
+
"paperId",
|
|
12
|
+
"title",
|
|
13
|
+
"abstract",
|
|
14
|
+
"year",
|
|
15
|
+
"authors",
|
|
16
|
+
"citationCount",
|
|
17
|
+
"influentialCitationCount",
|
|
18
|
+
"venue",
|
|
19
|
+
"externalIds",
|
|
20
|
+
"url",
|
|
21
|
+
].join(",");
|
|
22
|
+
const DETAIL_FIELDS = [
|
|
23
|
+
...SEARCH_FIELDS.split(","),
|
|
24
|
+
"referenceCount",
|
|
25
|
+
"isOpenAccess",
|
|
26
|
+
"openAccessPdf",
|
|
27
|
+
"publicationDate",
|
|
28
|
+
"journal",
|
|
29
|
+
].join(",");
|
|
30
|
+
/** Max retries on 429 / 5xx before giving up. */
|
|
31
|
+
const MAX_RETRIES = 2;
|
|
32
|
+
/** Request timeout in ms. */
|
|
33
|
+
const REQUEST_TIMEOUT_MS = 10_000;
|
|
34
|
+
// ── Helpers ──────────────────────────────────────────────────────────
|
|
35
|
+
function buildHeaders(apiKey) {
|
|
36
|
+
const headers = {
|
|
37
|
+
Accept: "application/json",
|
|
38
|
+
};
|
|
39
|
+
if (apiKey) {
|
|
40
|
+
headers["x-api-key"] = apiKey;
|
|
41
|
+
}
|
|
42
|
+
return headers;
|
|
43
|
+
}
|
|
44
|
+
async function fetchWithRetry(url, headers) {
|
|
45
|
+
let lastError;
|
|
46
|
+
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
47
|
+
try {
|
|
48
|
+
const res = await fetch(url, {
|
|
49
|
+
headers,
|
|
50
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
|
|
51
|
+
});
|
|
52
|
+
// Retry on 429 or 5xx
|
|
53
|
+
if ((res.status === 429 || res.status >= 500) && attempt < MAX_RETRIES) {
|
|
54
|
+
// Exponential backoff: 1s, 2s
|
|
55
|
+
await new Promise((r) => setTimeout(r, 1000 * (attempt + 1)));
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
return res;
|
|
59
|
+
}
|
|
60
|
+
catch (e) {
|
|
61
|
+
lastError = e;
|
|
62
|
+
if (attempt < MAX_RETRIES) {
|
|
63
|
+
await new Promise((r) => setTimeout(r, 1000 * (attempt + 1)));
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
throw lastError ?? new Error("fetchWithRetry exhausted");
|
|
69
|
+
}
|
|
70
|
+
// ── Public API ───────────────────────────────────────────────────────
|
|
71
|
+
/**
|
|
72
|
+
* Search for papers by keyword query.
|
|
73
|
+
*
|
|
74
|
+
* @see https://api.semanticscholar.org/api-docs/graph#tag/Paper-Data/operation/post_graph_get_papers_search
|
|
75
|
+
*/
|
|
76
|
+
export async function searchPapers(query, opts) {
|
|
77
|
+
const limit = Math.min(opts?.limit ?? 20, 100);
|
|
78
|
+
const offset = opts?.offset ?? 0;
|
|
79
|
+
const params = new URLSearchParams({
|
|
80
|
+
query,
|
|
81
|
+
fields: SEARCH_FIELDS,
|
|
82
|
+
limit: String(limit),
|
|
83
|
+
offset: String(offset),
|
|
84
|
+
});
|
|
85
|
+
const url = `${BASE_URL}/paper/search?${params}`;
|
|
86
|
+
try {
|
|
87
|
+
const res = await fetchWithRetry(url, buildHeaders(opts?.apiKey));
|
|
88
|
+
if (!res.ok) {
|
|
89
|
+
const status = res.status;
|
|
90
|
+
if (status === 400)
|
|
91
|
+
return { ok: false, status, reason: "not_found" };
|
|
92
|
+
if (status === 429)
|
|
93
|
+
return { ok: false, status, reason: "rate_limited" };
|
|
94
|
+
return { ok: false, status, reason: "upstream_error" };
|
|
95
|
+
}
|
|
96
|
+
const data = (await res.json());
|
|
97
|
+
return { ok: true, data };
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return { ok: false, reason: "network_error" };
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Get detailed information about a single paper.
|
|
105
|
+
*
|
|
106
|
+
* Accepts S2 paper ID, DOI (prefixed with "DOI:"), ArXiv ID ("ARXIV:"), etc.
|
|
107
|
+
*
|
|
108
|
+
* @see https://api.semanticscholar.org/api-docs/graph#tag/Paper-Data/operation/post_graph_get_paper
|
|
109
|
+
*/
|
|
110
|
+
export async function getPaperDetails(paperId, opts) {
|
|
111
|
+
const url = `${BASE_URL}/paper/${encodeURIComponent(paperId)}?fields=${DETAIL_FIELDS}`;
|
|
112
|
+
try {
|
|
113
|
+
const res = await fetchWithRetry(url, buildHeaders(opts?.apiKey));
|
|
114
|
+
if (!res.ok) {
|
|
115
|
+
const status = res.status;
|
|
116
|
+
if (status === 404)
|
|
117
|
+
return { ok: false, status, reason: "not_found" };
|
|
118
|
+
if (status === 429)
|
|
119
|
+
return { ok: false, status, reason: "rate_limited" };
|
|
120
|
+
return { ok: false, status, reason: "upstream_error" };
|
|
121
|
+
}
|
|
122
|
+
const data = (await res.json());
|
|
123
|
+
return { ok: true, data };
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
return { ok: false, reason: "network_error" };
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Get papers referenced by a given paper (its bibliography).
|
|
131
|
+
*
|
|
132
|
+
* Returns up to `limit` cited papers.
|
|
133
|
+
* @see https://api.semanticscholar.org/api-docs/graph#tag/Paper-Data/operation/get_graph_get_paper_references
|
|
134
|
+
*/
|
|
135
|
+
export async function getPaperReferences(paperId, opts) {
|
|
136
|
+
const limit = Math.min(opts?.limit ?? 100, 1000);
|
|
137
|
+
const params = new URLSearchParams({
|
|
138
|
+
fields: SEARCH_FIELDS,
|
|
139
|
+
limit: String(limit),
|
|
140
|
+
});
|
|
141
|
+
const url = `${BASE_URL}/paper/${encodeURIComponent(paperId)}/references?${params}`;
|
|
142
|
+
try {
|
|
143
|
+
const res = await fetchWithRetry(url, buildHeaders(opts?.apiKey));
|
|
144
|
+
if (!res.ok) {
|
|
145
|
+
const status = res.status;
|
|
146
|
+
if (status === 404)
|
|
147
|
+
return { ok: false, status, reason: "not_found" };
|
|
148
|
+
if (status === 429)
|
|
149
|
+
return { ok: false, status, reason: "rate_limited" };
|
|
150
|
+
return { ok: false, status, reason: "upstream_error" };
|
|
151
|
+
}
|
|
152
|
+
const body = (await res.json());
|
|
153
|
+
const papers = body.data
|
|
154
|
+
.map((edge) => edge.citedPaper)
|
|
155
|
+
.filter((p) => p != null && p.paperId != null);
|
|
156
|
+
return { ok: true, data: papers };
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
return { ok: false, reason: "network_error" };
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Get papers that cite a given paper.
|
|
164
|
+
*
|
|
165
|
+
* Returns up to `limit` citing papers.
|
|
166
|
+
* @see https://api.semanticscholar.org/api-docs/graph#tag/Paper-Data/operation/get_graph_get_paper_citations
|
|
167
|
+
*/
|
|
168
|
+
export async function getPaperCitations(paperId, opts) {
|
|
169
|
+
const limit = Math.min(opts?.limit ?? 100, 1000);
|
|
170
|
+
const params = new URLSearchParams({
|
|
171
|
+
fields: SEARCH_FIELDS,
|
|
172
|
+
limit: String(limit),
|
|
173
|
+
});
|
|
174
|
+
const url = `${BASE_URL}/paper/${encodeURIComponent(paperId)}/citations?${params}`;
|
|
175
|
+
try {
|
|
176
|
+
const res = await fetchWithRetry(url, buildHeaders(opts?.apiKey));
|
|
177
|
+
if (!res.ok) {
|
|
178
|
+
const status = res.status;
|
|
179
|
+
if (status === 404)
|
|
180
|
+
return { ok: false, status, reason: "not_found" };
|
|
181
|
+
if (status === 429)
|
|
182
|
+
return { ok: false, status, reason: "rate_limited" };
|
|
183
|
+
return { ok: false, status, reason: "upstream_error" };
|
|
184
|
+
}
|
|
185
|
+
const body = (await res.json());
|
|
186
|
+
const papers = body.data
|
|
187
|
+
.map((edge) => edge.citingPaper)
|
|
188
|
+
.filter((p) => p != null && p.paperId != null);
|
|
189
|
+
return { ok: true, data: papers };
|
|
190
|
+
}
|
|
191
|
+
catch {
|
|
192
|
+
return { ok: false, reason: "network_error" };
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/sources/semantic-scholar/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Semantic Scholar discovery provider.
|
|
3
|
+
*
|
|
4
|
+
* Adapts the S2 API client to the DiscoverProvider interface.
|
|
5
|
+
*/
|
|
6
|
+
import type { DiscoverCandidateCore, DiscoverProvider, DiscoverSearchOpts } from "../../discovery/types";
|
|
7
|
+
import { type S2Paper, type S2ClientOpts } from "./client";
|
|
8
|
+
/**
|
|
9
|
+
* Map an S2Paper to a DiscoverCandidateCore.
|
|
10
|
+
* Handles sparse records gracefully — every field may be null.
|
|
11
|
+
*/
|
|
12
|
+
export declare function s2PaperToCandidate(paper: S2Paper, position: number): DiscoverCandidateCore;
|
|
13
|
+
export declare class SemanticScholarProvider implements DiscoverProvider {
|
|
14
|
+
readonly name = "Semantic Scholar";
|
|
15
|
+
readonly sourceKind: "semantic-scholar";
|
|
16
|
+
readonly capabilities: readonly ["search"];
|
|
17
|
+
readonly isLocal = false;
|
|
18
|
+
private opts;
|
|
19
|
+
constructor(opts?: S2ClientOpts);
|
|
20
|
+
search(query: string, opts?: DiscoverSearchOpts): Promise<DiscoverCandidateCore[]>;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../../src/sources/semantic-scholar/provider.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EACV,qBAAqB,EACrB,gBAAgB,EAChB,kBAAkB,EACnB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAgB,KAAK,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,UAAU,CAAC;AAEzE;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,MAAM,GACf,qBAAqB,CA+BvB;AAED,qBAAa,uBAAwB,YAAW,gBAAgB;IAC9D,QAAQ,CAAC,IAAI,sBAAsB;IACnC,QAAQ,CAAC,UAAU,EAAG,kBAAkB,CAAU;IAClD,QAAQ,CAAC,YAAY,sBAAuB;IAC5C,QAAQ,CAAC,OAAO,SAAS;IAEzB,OAAO,CAAC,IAAI,CAAe;gBAEf,IAAI,CAAC,EAAE,YAAY;IAIzB,MAAM,CACV,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE,kBAAkB,GACxB,OAAO,CAAC,qBAAqB,EAAE,CAAC;CAkBpC"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Semantic Scholar discovery provider.
|
|
3
|
+
*
|
|
4
|
+
* Adapts the S2 API client to the DiscoverProvider interface.
|
|
5
|
+
*/
|
|
6
|
+
import { searchPapers } from "./client";
|
|
7
|
+
/**
|
|
8
|
+
* Map an S2Paper to a DiscoverCandidateCore.
|
|
9
|
+
* Handles sparse records gracefully — every field may be null.
|
|
10
|
+
*/
|
|
11
|
+
export function s2PaperToCandidate(paper, position) {
|
|
12
|
+
const doi = paper.externalIds?.DOI ?? null;
|
|
13
|
+
const authors = paper.authors
|
|
14
|
+
?.map((a) => a.name)
|
|
15
|
+
.filter(Boolean)
|
|
16
|
+
.join(", ") || null;
|
|
17
|
+
// Truncate abstract to ~200 chars for snippet
|
|
18
|
+
let abstractSnippet = null;
|
|
19
|
+
if (paper.abstract) {
|
|
20
|
+
abstractSnippet =
|
|
21
|
+
paper.abstract.length > 200
|
|
22
|
+
? paper.abstract.slice(0, 197) + "..."
|
|
23
|
+
: paper.abstract;
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
doi,
|
|
27
|
+
title: paper.title,
|
|
28
|
+
authors,
|
|
29
|
+
year: paper.year,
|
|
30
|
+
sources: ["semantic-scholar"],
|
|
31
|
+
score: position, // position-based; normalizeScore handles conversion to 0–1
|
|
32
|
+
semanticScholarId: paper.paperId,
|
|
33
|
+
citationCount: paper.citationCount,
|
|
34
|
+
influentialCitationCount: paper.influentialCitationCount,
|
|
35
|
+
abstractSnippet,
|
|
36
|
+
venue: paper.venue || null,
|
|
37
|
+
url: paper.url,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export class SemanticScholarProvider {
|
|
41
|
+
name = "Semantic Scholar";
|
|
42
|
+
sourceKind = "semantic-scholar";
|
|
43
|
+
capabilities = ["search"];
|
|
44
|
+
isLocal = false;
|
|
45
|
+
opts;
|
|
46
|
+
constructor(opts) {
|
|
47
|
+
this.opts = opts ?? {};
|
|
48
|
+
}
|
|
49
|
+
async search(query, opts) {
|
|
50
|
+
const limit = opts?.limit ?? 20;
|
|
51
|
+
const result = await searchPapers(query, {
|
|
52
|
+
...this.opts,
|
|
53
|
+
limit,
|
|
54
|
+
});
|
|
55
|
+
if (!result.ok) {
|
|
56
|
+
// Throw so the registry captures it as a provider error
|
|
57
|
+
// and the other providers continue working.
|
|
58
|
+
throw new Error(`Semantic Scholar search failed: ${result.reason}${result.status ? ` (${result.status})` : ""}`);
|
|
59
|
+
}
|
|
60
|
+
return result.data.data.map((paper, i) => s2PaperToCandidate(paper, i));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../../../src/sources/semantic-scholar/provider.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,OAAO,EAAE,YAAY,EAAmC,MAAM,UAAU,CAAC;AAEzE;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAChC,KAAc,EACd,QAAgB;IAEhB,MAAM,GAAG,GAAG,KAAK,CAAC,WAAW,EAAE,GAAG,IAAI,IAAI,CAAC;IAE3C,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO;QAC3B,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;SACnB,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC;IAEtB,8CAA8C;IAC9C,IAAI,eAAe,GAAkB,IAAI,CAAC;IAC1C,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;QACnB,eAAe;YACb,KAAK,CAAC,QAAQ,CAAC,MAAM,GAAG,GAAG;gBACzB,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,KAAK;gBACtC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC;IACvB,CAAC;IAED,OAAO;QACL,GAAG;QACH,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,OAAO;QACP,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,OAAO,EAAE,CAAC,kBAAkB,CAAC;QAC7B,KAAK,EAAE,QAAQ,EAAE,2DAA2D;QAC5E,iBAAiB,EAAE,KAAK,CAAC,OAAO;QAChC,aAAa,EAAE,KAAK,CAAC,aAAa;QAClC,wBAAwB,EAAE,KAAK,CAAC,wBAAwB;QACxD,eAAe;QACf,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,IAAI;QAC1B,GAAG,EAAE,KAAK,CAAC,GAAG;KACf,CAAC;AACJ,CAAC;AAED,MAAM,OAAO,uBAAuB;IACzB,IAAI,GAAG,kBAAkB,CAAC;IAC1B,UAAU,GAAG,kBAA2B,CAAC;IACzC,YAAY,GAAG,CAAC,QAAQ,CAAU,CAAC;IACnC,OAAO,GAAG,KAAK,CAAC;IAEjB,IAAI,CAAe;IAE3B,YAAY,IAAmB;QAC7B,IAAI,CAAC,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC;IACzB,CAAC;IAED,KAAK,CAAC,MAAM,CACV,KAAa,EACb,IAAyB;QAEzB,MAAM,KAAK,GAAG,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC;QAEhC,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,KAAK,EAAE;YACvC,GAAG,IAAI,CAAC,IAAI;YACZ,KAAK;SACN,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;YACf,wDAAwD;YACxD,4CAA4C;YAC5C,MAAM,IAAI,KAAK,CACb,mCAAmC,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAChG,CAAC;QACJ,CAAC;QAED,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;IAC1E,CAAC;CACF"}
|