sciverse 0.7.2__tar.gz → 0.8.0__tar.gz
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.
- {sciverse-0.7.2 → sciverse-0.8.0}/PKG-INFO +9 -1
- {sciverse-0.7.2 → sciverse-0.8.0}/README.md +8 -0
- {sciverse-0.7.2 → sciverse-0.8.0}/pyproject.toml +1 -1
- {sciverse-0.7.2 → sciverse-0.8.0}/src/sciverse/cli.py +10 -1
- {sciverse-0.7.2 → sciverse-0.8.0}/src/sciverse/client.py +19 -3
- {sciverse-0.7.2 → sciverse-0.8.0}/src/sciverse/tools.py +186 -3
- {sciverse-0.7.2 → sciverse-0.8.0}/src/sciverse/types.py +62 -5
- {sciverse-0.7.2 → sciverse-0.8.0}/uv.lock +1 -1
- {sciverse-0.7.2 → sciverse-0.8.0}/.gitignore +0 -0
- {sciverse-0.7.2 → sciverse-0.8.0}/src/sciverse/__init__.py +0 -0
- {sciverse-0.7.2 → sciverse-0.8.0}/src/sciverse/credentials.py +0 -0
- {sciverse-0.7.2 → sciverse-0.8.0}/src/sciverse/py.typed +0 -0
- {sciverse-0.7.2 → sciverse-0.8.0}/tests/__init__.py +0 -0
- {sciverse-0.7.2 → sciverse-0.8.0}/tests/test_cli.py +0 -0
- {sciverse-0.7.2 → sciverse-0.8.0}/tests/test_client.py +0 -0
- {sciverse-0.7.2 → sciverse-0.8.0}/tests/test_contract.py +0 -0
- {sciverse-0.7.2 → sciverse-0.8.0}/tests/test_credentials.py +0 -0
- {sciverse-0.7.2 → sciverse-0.8.0}/tests/test_tools.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sciverse
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.0
|
|
4
4
|
Summary: Sciverse Agent Tools — OpenAI/Anthropic/LangChain compatible tool schema and async client for Sciverse retrieval APIs
|
|
5
5
|
Project-URL: Homepage, https://github.com/opendatalab/Sciverse-Agent-Tools
|
|
6
6
|
Project-URL: Repository, https://github.com/opendatalab/Sciverse-Agent-Tools.git
|
|
@@ -131,6 +131,14 @@ await c.search_papers(
|
|
|
131
131
|
page_size=10,
|
|
132
132
|
)
|
|
133
133
|
|
|
134
|
+
# 1b. Entity collections — search authors / journals (set collection)
|
|
135
|
+
await c.search_papers(
|
|
136
|
+
collection="authors", # papers (default) / authors / sources
|
|
137
|
+
filters_advanced=[{"field": "summary_stats.h_index", "operator": "FILTER_OP_GTE", "value": 50}],
|
|
138
|
+
sort_advanced=[{"field": "cited_by_count", "order": "SORT_ORDER_DESC"}],
|
|
139
|
+
)
|
|
140
|
+
# Call list_catalog(collection="authors") to discover each collection's fields.
|
|
141
|
+
|
|
134
142
|
# 2. Natural-language semantic search (vector + BM25 hybrid, returns chunks)
|
|
135
143
|
await c.semantic_search(query="How does attention work?", top_k=10, mode="balanced")
|
|
136
144
|
|
|
@@ -114,6 +114,14 @@ await c.search_papers(
|
|
|
114
114
|
page_size=10,
|
|
115
115
|
)
|
|
116
116
|
|
|
117
|
+
# 1b. Entity collections — search authors / journals (set collection)
|
|
118
|
+
await c.search_papers(
|
|
119
|
+
collection="authors", # papers (default) / authors / sources
|
|
120
|
+
filters_advanced=[{"field": "summary_stats.h_index", "operator": "FILTER_OP_GTE", "value": 50}],
|
|
121
|
+
sort_advanced=[{"field": "cited_by_count", "order": "SORT_ORDER_DESC"}],
|
|
122
|
+
)
|
|
123
|
+
# Call list_catalog(collection="authors") to discover each collection's fields.
|
|
124
|
+
|
|
117
125
|
# 2. Natural-language semantic search (vector + BM25 hybrid, returns chunks)
|
|
118
126
|
await c.semantic_search(query="How does attention work?", top_k=10, mode="balanced")
|
|
119
127
|
|
|
@@ -142,6 +142,7 @@ def _cmd_search(args: argparse.Namespace) -> int:
|
|
|
142
142
|
if args.title_contains: kwargs["title_contains"] = args.title_contains
|
|
143
143
|
if args.abstract_contains: kwargs["abstract_contains"] = args.abstract_contains
|
|
144
144
|
if args.sort_by_year != "none": kwargs["sort_by_year"] = args.sort_by_year
|
|
145
|
+
if getattr(args, "collection", "papers") != "papers": kwargs["collection"] = args.collection
|
|
145
146
|
if args.freshness_boost != "NONE": kwargs["freshness_boost"] = args.freshness_boost
|
|
146
147
|
kwargs["page"] = args.page
|
|
147
148
|
kwargs["page_size"] = args.page_size
|
|
@@ -173,7 +174,10 @@ def _cmd_content(args: argparse.Namespace) -> int:
|
|
|
173
174
|
|
|
174
175
|
def _cmd_catalog(args: argparse.Namespace) -> int:
|
|
175
176
|
async def _do(client):
|
|
176
|
-
r = await client.list_catalog(
|
|
177
|
+
r = await client.list_catalog(
|
|
178
|
+
include_sample_values=args.samples,
|
|
179
|
+
collection=getattr(args, "collection", None),
|
|
180
|
+
)
|
|
177
181
|
_print_json(r)
|
|
178
182
|
|
|
179
183
|
return _run_with_client(_do)
|
|
@@ -241,6 +245,9 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
241
245
|
),
|
|
242
246
|
)
|
|
243
247
|
search.add_argument("query", nargs="?", default="", help="全文 BM25 关键词(可选)")
|
|
248
|
+
search.add_argument("--collection", choices=["papers", "authors", "sources"], default="papers",
|
|
249
|
+
help="实体集合(默认 papers)。authors/sources 的高级字段过滤请用 SDK 的 "
|
|
250
|
+
"filters_advanced / sort_advanced;CLI 主要支持 query 与 catalog 自省")
|
|
244
251
|
search.add_argument("--author", "--authors", action="append", default=[], dest="authors",
|
|
245
252
|
help="作者名(可多次传,任一命中即可)")
|
|
246
253
|
search.add_argument("--year-from", type=int, dest="year_from", help="起始年(含)")
|
|
@@ -283,6 +290,8 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
283
290
|
"catalog",
|
|
284
291
|
help="字段 introspection(GET /meta-catalog),第一次接入时建议先调",
|
|
285
292
|
)
|
|
293
|
+
cat.add_argument("--collection", choices=["papers", "authors", "sources"], default="papers",
|
|
294
|
+
help="字段目录所属实体集合(默认 papers)")
|
|
286
295
|
cat.add_argument("--samples", action="store_true",
|
|
287
296
|
help="拉枚举字段的取值样本(首次 OpenSearch terms agg,~几百 ms;之后 24h 缓存)")
|
|
288
297
|
cat.set_defaults(func=_cmd_catalog)
|
|
@@ -13,7 +13,7 @@ _PLATFORM = platform.system().lower() # "linux" | "darwin" | "windows"
|
|
|
13
13
|
_SOURCE = f"{_PLATFORM}-{_CHANNEL}"
|
|
14
14
|
|
|
15
15
|
|
|
16
|
-
_PASSTHROUGH = ("query", "page", "page_size", "fields", "freshness_boost")
|
|
16
|
+
_PASSTHROUGH = ("query", "page", "page_size", "fields", "freshness_boost", "collection")
|
|
17
17
|
_FRESHNESS_BOOST_VALUES = frozenset({"NONE", "MILD", "STRONG"})
|
|
18
18
|
|
|
19
19
|
|
|
@@ -65,6 +65,11 @@ def _to_backend_payload(kwargs: dict[str, Any]) -> dict[str, Any]:
|
|
|
65
65
|
"order": "SORT_ORDER_DESC" if sort_by_year == "desc" else "SORT_ORDER_ASC",
|
|
66
66
|
})
|
|
67
67
|
|
|
68
|
+
if (sa := kwargs.get("sort_advanced")) is not None:
|
|
69
|
+
for item in sa:
|
|
70
|
+
if item and item.get("field"):
|
|
71
|
+
sort.append({"field": item["field"], "order": item.get("order", "SORT_ORDER_DESC")})
|
|
72
|
+
|
|
68
73
|
if filters:
|
|
69
74
|
out["filters"] = filters
|
|
70
75
|
if sort:
|
|
@@ -151,14 +156,25 @@ class AgentToolsClient:
|
|
|
151
156
|
resp.raise_for_status()
|
|
152
157
|
return resp.json()
|
|
153
158
|
|
|
154
|
-
async def list_catalog(
|
|
159
|
+
async def list_catalog(
|
|
160
|
+
self,
|
|
161
|
+
*,
|
|
162
|
+
include_sample_values: bool = False,
|
|
163
|
+
include_field_stats: bool = False,
|
|
164
|
+
collection: str | None = None,
|
|
165
|
+
) -> dict[str, Any]:
|
|
155
166
|
"""对应 GET /meta-catalog。
|
|
156
167
|
|
|
157
168
|
返回字段 catalog:每个字段的名称 / 类型 / filterable / sortable / default_returned /
|
|
158
169
|
描述 / 适用 FilterOperator,外加 enum-like 字段的样本值(include_sample_values=True 时)。
|
|
170
|
+
collection 指定实体集合(papers 默认 / authors / sources),各 collection 字段集不同。
|
|
159
171
|
Agent 第一次接触 Sciverse 或碰到字段不确定时建议先调一次再构造 search_papers。
|
|
160
172
|
"""
|
|
161
|
-
params = {"include_sample_values": str(include_sample_values).lower()}
|
|
173
|
+
params: dict[str, str] = {"include_sample_values": str(include_sample_values).lower()}
|
|
174
|
+
if include_field_stats:
|
|
175
|
+
params["include_field_stats"] = "true"
|
|
176
|
+
if collection:
|
|
177
|
+
params["collection"] = collection
|
|
162
178
|
resp = await self._client.get("/meta-catalog", params=params)
|
|
163
179
|
resp.raise_for_status()
|
|
164
180
|
return resp.json()
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Auto-generated. Do not edit. Run scripts/build.sh."""
|
|
2
2
|
import json
|
|
3
3
|
|
|
4
|
-
TOOLS_VERSION = "0.
|
|
4
|
+
TOOLS_VERSION = "0.8.0"
|
|
5
5
|
|
|
6
6
|
OPENAI_TOOLS = json.loads(r"""
|
|
7
7
|
[
|
|
@@ -13,6 +13,17 @@ OPENAI_TOOLS = json.loads(r"""
|
|
|
13
13
|
"parameters": {
|
|
14
14
|
"type": "object",
|
|
15
15
|
"properties": {
|
|
16
|
+
"collection": {
|
|
17
|
+
"type": "string",
|
|
18
|
+
"enum": [
|
|
19
|
+
"papers",
|
|
20
|
+
"authors",
|
|
21
|
+
"sources"
|
|
22
|
+
],
|
|
23
|
+
"default": "papers",
|
|
24
|
+
"description": "检索的实体集合。papers(默认,论文)/ authors(作者)/ sources(来源期刊)。 各 collection 字段集不同,用 list_catalog(collection=<name>)学习对应 schema。 注意:本工具的便捷字段(authors/journals/year_from/subjects 等)只对 papers 有意义; 查 authors/sources 时改用 filters_advanced + 该 collection 的字段名(如 authors 的 summary_stats.h_index / orcid,sources 的 issn / is_oa)。authors 用 orcid、 sources 用 issn 与论文检索结果关联。",
|
|
25
|
+
"x-en-description": "Entity collection to search. papers (default) / authors / sources. Each collection has its own field schema — call list_catalog(collection=<name>). The convenience fields (authors/journals/year_from/subjects) apply to papers only; for authors/sources use filters_advanced with that collection's field names."
|
|
26
|
+
},
|
|
16
27
|
"query": {
|
|
17
28
|
"type": "string",
|
|
18
29
|
"description": "BM25 全文关键词,匹配标题/摘要/期刊名/关键词字段。留空则纯靠结构化过滤。"
|
|
@@ -69,6 +80,7 @@ OPENAI_TOOLS = json.loads(r"""
|
|
|
69
80
|
},
|
|
70
81
|
"operator": {
|
|
71
82
|
"type": "string",
|
|
83
|
+
"description": "过滤操作符。MATCH(分词模糊)适用于 author、keywords(输入 \"Hinton\" 命中 \"Geoffrey Hinton\"); MATCH_PHRASE(短语模糊)适用于 publication_venue_name_unified,整词连续匹配(\"Nature\" 命中 \"Nature Communications\";非前缀匹配,\"Nature Comm\" 不会命中); doi 用 EQ,服务端归一化(去 doi.org 前缀+转小写)后精确匹配。MATCH/MATCH_PHRASE 仅对配了 text 子字段的字段有效。",
|
|
72
84
|
"enum": [
|
|
73
85
|
"FILTER_OP_EQ",
|
|
74
86
|
"FILTER_OP_NE",
|
|
@@ -78,7 +90,9 @@ OPENAI_TOOLS = json.loads(r"""
|
|
|
78
90
|
"FILTER_OP_LTE",
|
|
79
91
|
"FILTER_OP_IN",
|
|
80
92
|
"FILTER_OP_NIN",
|
|
81
|
-
"FILTER_OP_CONTAINS"
|
|
93
|
+
"FILTER_OP_CONTAINS",
|
|
94
|
+
"FILTER_OP_MATCH",
|
|
95
|
+
"FILTER_OP_MATCH_PHRASE"
|
|
82
96
|
],
|
|
83
97
|
"default": "FILTER_OP_EQ"
|
|
84
98
|
},
|
|
@@ -86,6 +100,30 @@ OPENAI_TOOLS = json.loads(r"""
|
|
|
86
100
|
}
|
|
87
101
|
}
|
|
88
102
|
},
|
|
103
|
+
"sort_advanced": {
|
|
104
|
+
"type": "array",
|
|
105
|
+
"description": "高级排序逃生舱(按任意可排序字段)。papers 用 sort_by_year 即可; authors/sources 想按 h-index / 被引 / works_count 排序时用本字段。 与 query 互斥(query 走相关性排序)。",
|
|
106
|
+
"items": {
|
|
107
|
+
"type": "object",
|
|
108
|
+
"required": [
|
|
109
|
+
"field",
|
|
110
|
+
"order"
|
|
111
|
+
],
|
|
112
|
+
"properties": {
|
|
113
|
+
"field": {
|
|
114
|
+
"type": "string"
|
|
115
|
+
},
|
|
116
|
+
"order": {
|
|
117
|
+
"type": "string",
|
|
118
|
+
"enum": [
|
|
119
|
+
"SORT_ORDER_DESC",
|
|
120
|
+
"SORT_ORDER_ASC"
|
|
121
|
+
],
|
|
122
|
+
"default": "SORT_ORDER_DESC"
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
},
|
|
89
127
|
"sort_by_year": {
|
|
90
128
|
"type": "string",
|
|
91
129
|
"enum": [
|
|
@@ -175,16 +213,71 @@ OPENAI_TOOLS = json.loads(r"""
|
|
|
175
213
|
"parameters": {
|
|
176
214
|
"type": "object",
|
|
177
215
|
"properties": {
|
|
216
|
+
"collection": {
|
|
217
|
+
"type": "string",
|
|
218
|
+
"enum": [
|
|
219
|
+
"papers",
|
|
220
|
+
"authors",
|
|
221
|
+
"sources"
|
|
222
|
+
],
|
|
223
|
+
"default": "papers",
|
|
224
|
+
"description": "字段 catalog 所属实体集合。papers(默认)/ authors / sources,各 collection 字段不同。"
|
|
225
|
+
},
|
|
178
226
|
"include_sample_values": {
|
|
179
227
|
"type": "boolean",
|
|
180
228
|
"default": false,
|
|
181
229
|
"description": "是否拉取 enum-like 字段的取值样本。false 仅返回静态 schema(毫秒级);true 触发 OpenSearch terms agg(首次几百毫秒,之后 24h 走缓存)。"
|
|
230
|
+
},
|
|
231
|
+
"include_field_stats": {
|
|
232
|
+
"type": "boolean",
|
|
233
|
+
"default": false,
|
|
234
|
+
"description": "是否返回字段统计(keyword 字段基数 + 数值字段 min/max/avg/p50/p95)。触发 OpenSearch 聚合,缓存 24h。"
|
|
182
235
|
}
|
|
183
236
|
},
|
|
184
237
|
"required": []
|
|
185
238
|
}
|
|
186
239
|
}
|
|
187
240
|
},
|
|
241
|
+
{
|
|
242
|
+
"type": "function",
|
|
243
|
+
"function": {
|
|
244
|
+
"name": "list_paper_relations",
|
|
245
|
+
"description": "分页返回某篇论文的引用关系完整列表。citations/references/related_works 是无界数组\n(高被引文献可达数千条),search_papers 只内联截断少量,要翻完整列表用本接口。\n适用:「论文 X 引用了哪些文献」(relation=REFERENCES)、「哪些文献引用了论文 X」\n(relation=CITATIONS)、「与论文 X 相关的工作」(relation=RELATED_WORKS)。\n注意:CITATIONS(被引:谁引用了我)与 REFERENCES(参考文献:我引用了谁)方向相反。\n典型链路:先 search_papers / semantic_search 拿到 unique_id,再用本接口按 relation 分页。",
|
|
246
|
+
"parameters": {
|
|
247
|
+
"type": "object",
|
|
248
|
+
"required": [
|
|
249
|
+
"unique_id",
|
|
250
|
+
"relation"
|
|
251
|
+
],
|
|
252
|
+
"properties": {
|
|
253
|
+
"unique_id": {
|
|
254
|
+
"type": "string",
|
|
255
|
+
"description": "目标论文 unique_id(如 paper:10.1038/xxx),来自 search_papers / semantic_search;勿传 doc_id。"
|
|
256
|
+
},
|
|
257
|
+
"relation": {
|
|
258
|
+
"type": "string",
|
|
259
|
+
"enum": [
|
|
260
|
+
"CITATIONS",
|
|
261
|
+
"REFERENCES",
|
|
262
|
+
"RELATED_WORKS"
|
|
263
|
+
],
|
|
264
|
+
"description": "关系类型。CITATIONS=被引(谁引用了我);REFERENCES=参考文献(我引用了谁);RELATED_WORKS=相关工作。"
|
|
265
|
+
},
|
|
266
|
+
"page": {
|
|
267
|
+
"type": "integer",
|
|
268
|
+
"default": 1,
|
|
269
|
+
"minimum": 1
|
|
270
|
+
},
|
|
271
|
+
"page_size": {
|
|
272
|
+
"type": "integer",
|
|
273
|
+
"default": 25,
|
|
274
|
+
"minimum": 1,
|
|
275
|
+
"maximum": 200
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
},
|
|
188
281
|
{
|
|
189
282
|
"type": "function",
|
|
190
283
|
"function": {
|
|
@@ -245,6 +338,17 @@ ANTHROPIC_TOOLS = json.loads(r"""
|
|
|
245
338
|
"input_schema": {
|
|
246
339
|
"type": "object",
|
|
247
340
|
"properties": {
|
|
341
|
+
"collection": {
|
|
342
|
+
"type": "string",
|
|
343
|
+
"enum": [
|
|
344
|
+
"papers",
|
|
345
|
+
"authors",
|
|
346
|
+
"sources"
|
|
347
|
+
],
|
|
348
|
+
"default": "papers",
|
|
349
|
+
"description": "检索的实体集合。papers(默认,论文)/ authors(作者)/ sources(来源期刊)。 各 collection 字段集不同,用 list_catalog(collection=<name>)学习对应 schema。 注意:本工具的便捷字段(authors/journals/year_from/subjects 等)只对 papers 有意义; 查 authors/sources 时改用 filters_advanced + 该 collection 的字段名(如 authors 的 summary_stats.h_index / orcid,sources 的 issn / is_oa)。authors 用 orcid、 sources 用 issn 与论文检索结果关联。",
|
|
350
|
+
"x-en-description": "Entity collection to search. papers (default) / authors / sources. Each collection has its own field schema — call list_catalog(collection=<name>). The convenience fields (authors/journals/year_from/subjects) apply to papers only; for authors/sources use filters_advanced with that collection's field names."
|
|
351
|
+
},
|
|
248
352
|
"query": {
|
|
249
353
|
"type": "string",
|
|
250
354
|
"description": "BM25 全文关键词,匹配标题/摘要/期刊名/关键词字段。留空则纯靠结构化过滤。"
|
|
@@ -301,6 +405,7 @@ ANTHROPIC_TOOLS = json.loads(r"""
|
|
|
301
405
|
},
|
|
302
406
|
"operator": {
|
|
303
407
|
"type": "string",
|
|
408
|
+
"description": "过滤操作符。MATCH(分词模糊)适用于 author、keywords(输入 \"Hinton\" 命中 \"Geoffrey Hinton\"); MATCH_PHRASE(短语模糊)适用于 publication_venue_name_unified,整词连续匹配(\"Nature\" 命中 \"Nature Communications\";非前缀匹配,\"Nature Comm\" 不会命中); doi 用 EQ,服务端归一化(去 doi.org 前缀+转小写)后精确匹配。MATCH/MATCH_PHRASE 仅对配了 text 子字段的字段有效。",
|
|
304
409
|
"enum": [
|
|
305
410
|
"FILTER_OP_EQ",
|
|
306
411
|
"FILTER_OP_NE",
|
|
@@ -310,7 +415,9 @@ ANTHROPIC_TOOLS = json.loads(r"""
|
|
|
310
415
|
"FILTER_OP_LTE",
|
|
311
416
|
"FILTER_OP_IN",
|
|
312
417
|
"FILTER_OP_NIN",
|
|
313
|
-
"FILTER_OP_CONTAINS"
|
|
418
|
+
"FILTER_OP_CONTAINS",
|
|
419
|
+
"FILTER_OP_MATCH",
|
|
420
|
+
"FILTER_OP_MATCH_PHRASE"
|
|
314
421
|
],
|
|
315
422
|
"default": "FILTER_OP_EQ"
|
|
316
423
|
},
|
|
@@ -318,6 +425,30 @@ ANTHROPIC_TOOLS = json.loads(r"""
|
|
|
318
425
|
}
|
|
319
426
|
}
|
|
320
427
|
},
|
|
428
|
+
"sort_advanced": {
|
|
429
|
+
"type": "array",
|
|
430
|
+
"description": "高级排序逃生舱(按任意可排序字段)。papers 用 sort_by_year 即可; authors/sources 想按 h-index / 被引 / works_count 排序时用本字段。 与 query 互斥(query 走相关性排序)。",
|
|
431
|
+
"items": {
|
|
432
|
+
"type": "object",
|
|
433
|
+
"required": [
|
|
434
|
+
"field",
|
|
435
|
+
"order"
|
|
436
|
+
],
|
|
437
|
+
"properties": {
|
|
438
|
+
"field": {
|
|
439
|
+
"type": "string"
|
|
440
|
+
},
|
|
441
|
+
"order": {
|
|
442
|
+
"type": "string",
|
|
443
|
+
"enum": [
|
|
444
|
+
"SORT_ORDER_DESC",
|
|
445
|
+
"SORT_ORDER_ASC"
|
|
446
|
+
],
|
|
447
|
+
"default": "SORT_ORDER_DESC"
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
},
|
|
321
452
|
"sort_by_year": {
|
|
322
453
|
"type": "string",
|
|
323
454
|
"enum": [
|
|
@@ -401,15 +532,67 @@ ANTHROPIC_TOOLS = json.loads(r"""
|
|
|
401
532
|
"input_schema": {
|
|
402
533
|
"type": "object",
|
|
403
534
|
"properties": {
|
|
535
|
+
"collection": {
|
|
536
|
+
"type": "string",
|
|
537
|
+
"enum": [
|
|
538
|
+
"papers",
|
|
539
|
+
"authors",
|
|
540
|
+
"sources"
|
|
541
|
+
],
|
|
542
|
+
"default": "papers",
|
|
543
|
+
"description": "字段 catalog 所属实体集合。papers(默认)/ authors / sources,各 collection 字段不同。"
|
|
544
|
+
},
|
|
404
545
|
"include_sample_values": {
|
|
405
546
|
"type": "boolean",
|
|
406
547
|
"default": false,
|
|
407
548
|
"description": "是否拉取 enum-like 字段的取值样本。false 仅返回静态 schema(毫秒级);true 触发 OpenSearch terms agg(首次几百毫秒,之后 24h 走缓存)。"
|
|
549
|
+
},
|
|
550
|
+
"include_field_stats": {
|
|
551
|
+
"type": "boolean",
|
|
552
|
+
"default": false,
|
|
553
|
+
"description": "是否返回字段统计(keyword 字段基数 + 数值字段 min/max/avg/p50/p95)。触发 OpenSearch 聚合,缓存 24h。"
|
|
408
554
|
}
|
|
409
555
|
},
|
|
410
556
|
"required": []
|
|
411
557
|
}
|
|
412
558
|
},
|
|
559
|
+
{
|
|
560
|
+
"name": "list_paper_relations",
|
|
561
|
+
"description": "分页返回某篇论文的引用关系完整列表。citations/references/related_works 是无界数组\n(高被引文献可达数千条),search_papers 只内联截断少量,要翻完整列表用本接口。\n适用:「论文 X 引用了哪些文献」(relation=REFERENCES)、「哪些文献引用了论文 X」\n(relation=CITATIONS)、「与论文 X 相关的工作」(relation=RELATED_WORKS)。\n注意:CITATIONS(被引:谁引用了我)与 REFERENCES(参考文献:我引用了谁)方向相反。\n典型链路:先 search_papers / semantic_search 拿到 unique_id,再用本接口按 relation 分页。",
|
|
562
|
+
"input_schema": {
|
|
563
|
+
"type": "object",
|
|
564
|
+
"required": [
|
|
565
|
+
"unique_id",
|
|
566
|
+
"relation"
|
|
567
|
+
],
|
|
568
|
+
"properties": {
|
|
569
|
+
"unique_id": {
|
|
570
|
+
"type": "string",
|
|
571
|
+
"description": "目标论文 unique_id(如 paper:10.1038/xxx),来自 search_papers / semantic_search;勿传 doc_id。"
|
|
572
|
+
},
|
|
573
|
+
"relation": {
|
|
574
|
+
"type": "string",
|
|
575
|
+
"enum": [
|
|
576
|
+
"CITATIONS",
|
|
577
|
+
"REFERENCES",
|
|
578
|
+
"RELATED_WORKS"
|
|
579
|
+
],
|
|
580
|
+
"description": "关系类型。CITATIONS=被引(谁引用了我);REFERENCES=参考文献(我引用了谁);RELATED_WORKS=相关工作。"
|
|
581
|
+
},
|
|
582
|
+
"page": {
|
|
583
|
+
"type": "integer",
|
|
584
|
+
"default": 1,
|
|
585
|
+
"minimum": 1
|
|
586
|
+
},
|
|
587
|
+
"page_size": {
|
|
588
|
+
"type": "integer",
|
|
589
|
+
"default": 25,
|
|
590
|
+
"minimum": 1,
|
|
591
|
+
"maximum": 200
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
},
|
|
413
596
|
{
|
|
414
597
|
"name": "read_content",
|
|
415
598
|
"description": "按字节区间读取文献原文片段。通常配合 semantic_search 返回的 doc_id/offset 使用,\n用于扩展上下文(往前/往后读更多字节)。\n返回:UTF-8 文本片段、bytes_returned、next_offset、是否还有后续。",
|
|
@@ -9,7 +9,21 @@ from typing import Any
|
|
|
9
9
|
from pydantic import BaseModel, Field
|
|
10
10
|
|
|
11
11
|
|
|
12
|
+
class Collection(Enum):
|
|
13
|
+
"""
|
|
14
|
+
检索的实体集合。papers(默认,论文)/ authors(作者)/ sources(来源期刊)。 各 collection 字段集不同,用 list_catalog(collection=<name>)学习对应 schema。 注意:本工具的便捷字段(authors/journals/year_from/subjects 等)只对 papers 有意义; 查 authors/sources 时改用 filters_advanced + 该 collection 的字段名(如 authors 的 summary_stats.h_index / orcid,sources 的 issn / is_oa)。authors 用 orcid、 sources 用 issn 与论文检索结果关联。
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
papers = "papers"
|
|
18
|
+
authors = "authors"
|
|
19
|
+
sources = "sources"
|
|
20
|
+
|
|
21
|
+
|
|
12
22
|
class Operator(Enum):
|
|
23
|
+
"""
|
|
24
|
+
过滤操作符。MATCH(分词模糊)适用于 author、keywords(输入 "Hinton" 命中 "Geoffrey Hinton"); MATCH_PHRASE(短语模糊)适用于 publication_venue_name_unified,整词连续匹配("Nature" 命中 "Nature Communications";非前缀匹配,"Nature Comm" 不会命中); doi 用 EQ,服务端归一化(去 doi.org 前缀+转小写)后精确匹配。MATCH/MATCH_PHRASE 仅对配了 text 子字段的字段有效。
|
|
25
|
+
"""
|
|
26
|
+
|
|
13
27
|
FILTER_OP_EQ = "FILTER_OP_EQ"
|
|
14
28
|
FILTER_OP_NE = "FILTER_OP_NE"
|
|
15
29
|
FILTER_OP_GT = "FILTER_OP_GT"
|
|
@@ -19,14 +33,29 @@ class Operator(Enum):
|
|
|
19
33
|
FILTER_OP_IN = "FILTER_OP_IN"
|
|
20
34
|
FILTER_OP_NIN = "FILTER_OP_NIN"
|
|
21
35
|
FILTER_OP_CONTAINS = "FILTER_OP_CONTAINS"
|
|
36
|
+
FILTER_OP_MATCH = "FILTER_OP_MATCH"
|
|
37
|
+
FILTER_OP_MATCH_PHRASE = "FILTER_OP_MATCH_PHRASE"
|
|
22
38
|
|
|
23
39
|
|
|
24
40
|
class FiltersAdvancedItem(BaseModel):
|
|
25
41
|
field: str
|
|
26
|
-
operator: Operator | None =
|
|
42
|
+
operator: Operator | None = Field(
|
|
43
|
+
"FILTER_OP_EQ",
|
|
44
|
+
description='过滤操作符。MATCH(分词模糊)适用于 author、keywords(输入 "Hinton" 命中 "Geoffrey Hinton"); MATCH_PHRASE(短语模糊)适用于 publication_venue_name_unified,整词连续匹配("Nature" 命中 "Nature Communications";非前缀匹配,"Nature Comm" 不会命中); doi 用 EQ,服务端归一化(去 doi.org 前缀+转小写)后精确匹配。MATCH/MATCH_PHRASE 仅对配了 text 子字段的字段有效。',
|
|
45
|
+
)
|
|
27
46
|
value: Any
|
|
28
47
|
|
|
29
48
|
|
|
49
|
+
class Order(Enum):
|
|
50
|
+
SORT_ORDER_DESC = "SORT_ORDER_DESC"
|
|
51
|
+
SORT_ORDER_ASC = "SORT_ORDER_ASC"
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class SortAdvancedItem(BaseModel):
|
|
55
|
+
field: str
|
|
56
|
+
order: Order
|
|
57
|
+
|
|
58
|
+
|
|
30
59
|
class SortByYear(Enum):
|
|
31
60
|
desc = "desc"
|
|
32
61
|
asc = "asc"
|
|
@@ -48,6 +77,10 @@ class FreshnessBoost(Enum):
|
|
|
48
77
|
|
|
49
78
|
|
|
50
79
|
class SearchPapersRequest(BaseModel):
|
|
80
|
+
collection: Collection | None = Field(
|
|
81
|
+
"papers",
|
|
82
|
+
description="检索的实体集合。papers(默认,论文)/ authors(作者)/ sources(来源期刊)。 各 collection 字段集不同,用 list_catalog(collection=<name>)学习对应 schema。 注意:本工具的便捷字段(authors/journals/year_from/subjects 等)只对 papers 有意义; 查 authors/sources 时改用 filters_advanced + 该 collection 的字段名(如 authors 的 summary_stats.h_index / orcid,sources 的 issn / is_oa)。authors 用 orcid、 sources 用 issn 与论文检索结果关联。",
|
|
83
|
+
)
|
|
51
84
|
query: str | None = Field(
|
|
52
85
|
None,
|
|
53
86
|
description="BM25 全文关键词,匹配标题/摘要/期刊名/关键词字段。留空则纯靠结构化过滤。",
|
|
@@ -74,6 +107,10 @@ class SearchPapersRequest(BaseModel):
|
|
|
74
107
|
filters_advanced: list[FiltersAdvancedItem] | None = Field(
|
|
75
108
|
None, description="高级过滤逃生舱(仅当上述字段不够用时使用)。"
|
|
76
109
|
)
|
|
110
|
+
sort_advanced: list[SortAdvancedItem] | None = Field(
|
|
111
|
+
None,
|
|
112
|
+
description="高级排序逃生舱(按任意可排序字段)。papers 用 sort_by_year 即可; authors/sources 想按 h-index / 被引 / works_count 排序时用本字段。 与 query 互斥(query 走相关性排序)。",
|
|
113
|
+
)
|
|
77
114
|
sort_by_year: SortByYear | None = "desc"
|
|
78
115
|
freshness_boost: FreshnessBoost | None = Field(
|
|
79
116
|
"NONE",
|
|
@@ -83,6 +120,11 @@ class SearchPapersRequest(BaseModel):
|
|
|
83
120
|
page_size: int | None = Field(10, ge=1, le=50)
|
|
84
121
|
|
|
85
122
|
|
|
123
|
+
class AuthorItem(BaseModel):
|
|
124
|
+
name: str | None = None
|
|
125
|
+
orcid: str | None = None
|
|
126
|
+
|
|
127
|
+
|
|
86
128
|
class PaperMetadata(BaseModel):
|
|
87
129
|
"""
|
|
88
130
|
文献元数据。字段名与 metadata-service 后端 `fields.py` 的真实字段一致,
|
|
@@ -106,9 +148,9 @@ class PaperMetadata(BaseModel):
|
|
|
106
148
|
description="全文 artifact 的内容哈希(sha256)。仅当文档存在全文时返回;元数据-only 记录无此字段,且无法用 doc_id 过滤命中。",
|
|
107
149
|
)
|
|
108
150
|
title: str
|
|
109
|
-
author: list[
|
|
151
|
+
author: list[AuthorItem] | None = Field(
|
|
110
152
|
None,
|
|
111
|
-
description=
|
|
153
|
+
description='作者列表(OS object 数组,子字段 name/orcid)。按作者名检索:精确走 author.name.keyword、模糊 MATCH 走 author.name;对外过滤仍传 field "author"。',
|
|
112
154
|
)
|
|
113
155
|
abstract: str | None = None
|
|
114
156
|
publication_venue_name_unified: str | None = Field(
|
|
@@ -201,10 +243,25 @@ class ApiError(BaseModel):
|
|
|
201
243
|
|
|
202
244
|
|
|
203
245
|
class SearchPapersResponse(BaseModel):
|
|
204
|
-
|
|
205
|
-
|
|
246
|
+
results: list[PaperMetadata] = Field(
|
|
247
|
+
..., description="命中论文列表(后端字段名为 results,非 hits)。"
|
|
248
|
+
)
|
|
249
|
+
total_count: int = Field(
|
|
250
|
+
...,
|
|
251
|
+
description="命中总数;超过 10000 会被截断为 10000,需精确值时改用深翻页/计数。",
|
|
252
|
+
)
|
|
206
253
|
page: int
|
|
207
254
|
page_size: int
|
|
255
|
+
total_pages: int | None = Field(None, description="总页数。")
|
|
256
|
+
next_cursor: str | None = Field(
|
|
257
|
+
None,
|
|
258
|
+
description="深翻页游标,为空表示无更多。page*page_size>10000 时必须改用 cursor(把此值回填到请求的 cursor)。",
|
|
259
|
+
)
|
|
260
|
+
search_time_ms: float | None = Field(None, description="检索耗时(毫秒)。")
|
|
261
|
+
request_tokens: int | None = Field(None, description="输入 query 的 token 数。")
|
|
262
|
+
response_tokens: int | None = Field(
|
|
263
|
+
None, description="输出结果文本字段的 token 数。"
|
|
264
|
+
)
|
|
208
265
|
|
|
209
266
|
|
|
210
267
|
class SemanticSearchResponse(BaseModel):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|