scitex 2.15.3__py3-none-any.whl → 2.15.5__py3-none-any.whl
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.
- scitex/_mcp_resources/__init__.py +2 -0
- scitex/_mcp_resources/_scholar.py +148 -0
- scitex/_mcp_tools/canvas.py +49 -15
- scitex/_mcp_tools/scholar.py +50 -99
- scitex/canvas/__init__.py +169 -287
- scitex/canvas/_legacy.py +171 -0
- scitex/canvas/mcp_server.py +16 -3
- scitex/capture/mcp_server.py +16 -2
- scitex/cli/scholar/__init__.py +55 -28
- scitex/cli/scholar/_crossref_scitex.py +25 -266
- scitex/cli/scholar/_openalex_scitex.py +55 -0
- scitex/scholar/__init__.py +14 -9
- scitex/scholar/_mcp/crossref_tool_schemas.py +133 -0
- scitex/scholar/_mcp/openalex_handlers.py +212 -0
- scitex/scholar/_mcp/openalex_tool_schemas.py +96 -0
- scitex/scholar/_mcp/tool_schemas.py +16 -1
- scitex/scholar/local_dbs/__init__.py +31 -0
- scitex/scholar/local_dbs/crossref_scitex.py +30 -0
- scitex/scholar/local_dbs/openalex_scitex.py +30 -0
- scitex/scholar/mcp_server.py +59 -4
- scitex/stats/mcp_server.py +16 -3
- scitex/template/mcp_server.py +16 -3
- scitex/ui/mcp_server.py +16 -3
- {scitex-2.15.3.dist-info → scitex-2.15.5.dist-info}/METADATA +1 -1
- {scitex-2.15.3.dist-info → scitex-2.15.5.dist-info}/RECORD +28 -20
- scitex/scholar/crossref_scitex.py +0 -367
- {scitex-2.15.3.dist-info → scitex-2.15.5.dist-info}/WHEEL +0 -0
- {scitex-2.15.3.dist-info → scitex-2.15.5.dist-info}/entry_points.txt +0 -0
- {scitex-2.15.3.dist-info → scitex-2.15.5.dist-info}/licenses/LICENSE +0 -0
scitex/canvas/mcp_server.py
CHANGED
|
@@ -3,8 +3,12 @@
|
|
|
3
3
|
# File: src/scitex/canvas/mcp_server.py
|
|
4
4
|
# ----------------------------------------
|
|
5
5
|
|
|
6
|
-
"""
|
|
7
|
-
|
|
6
|
+
"""MCP Server for SciTeX canvas - Multi-panel figure composition.
|
|
7
|
+
|
|
8
|
+
.. deprecated::
|
|
9
|
+
This standalone server is deprecated. Use the unified scitex MCP server:
|
|
10
|
+
CLI: scitex serve
|
|
11
|
+
Python: from scitex.mcp_server import run_server
|
|
8
12
|
|
|
9
13
|
Provides tools for:
|
|
10
14
|
- Creating canvas workspaces
|
|
@@ -15,6 +19,15 @@ Provides tools for:
|
|
|
15
19
|
|
|
16
20
|
from __future__ import annotations
|
|
17
21
|
|
|
22
|
+
import warnings
|
|
23
|
+
|
|
24
|
+
warnings.warn(
|
|
25
|
+
"scitex.canvas.mcp_server is deprecated. Use 'scitex serve' or "
|
|
26
|
+
"'from scitex.mcp_server import run_server' for the unified MCP server.",
|
|
27
|
+
DeprecationWarning,
|
|
28
|
+
stacklevel=2,
|
|
29
|
+
)
|
|
30
|
+
|
|
18
31
|
import asyncio
|
|
19
32
|
|
|
20
33
|
# Graceful MCP dependency handling
|
|
@@ -126,7 +139,7 @@ async def _run_server():
|
|
|
126
139
|
|
|
127
140
|
|
|
128
141
|
def main():
|
|
129
|
-
"""
|
|
142
|
+
"""Run the MCP server."""
|
|
130
143
|
if not MCP_AVAILABLE:
|
|
131
144
|
import sys
|
|
132
145
|
|
scitex/capture/mcp_server.py
CHANGED
|
@@ -10,11 +10,25 @@ __FILE__ = "./src/scitex/capture/mcp_server.py"
|
|
|
10
10
|
__DIR__ = os.path.dirname(__FILE__)
|
|
11
11
|
# ----------------------------------------
|
|
12
12
|
|
|
13
|
-
"""
|
|
14
|
-
|
|
13
|
+
"""MCP Server for SciTeX Capture - Screen Capture for Python.
|
|
14
|
+
|
|
15
|
+
.. deprecated::
|
|
16
|
+
This standalone server is deprecated. Use the unified scitex MCP server:
|
|
17
|
+
CLI: scitex serve
|
|
18
|
+
Python: from scitex.mcp_server import run_server
|
|
19
|
+
|
|
15
20
|
Provides screenshot capture capabilities via Model Context Protocol.
|
|
16
21
|
"""
|
|
17
22
|
|
|
23
|
+
import warnings
|
|
24
|
+
|
|
25
|
+
warnings.warn(
|
|
26
|
+
"scitex.capture.mcp_server is deprecated. Use 'scitex serve' or "
|
|
27
|
+
"'from scitex.mcp_server import run_server' for the unified MCP server.",
|
|
28
|
+
DeprecationWarning,
|
|
29
|
+
stacklevel=2,
|
|
30
|
+
)
|
|
31
|
+
|
|
18
32
|
import asyncio
|
|
19
33
|
import base64
|
|
20
34
|
from datetime import datetime
|
scitex/cli/scholar/__init__.py
CHANGED
|
@@ -21,6 +21,11 @@ CrossRef database (167M+ papers via crossref-local):
|
|
|
21
21
|
scitex scholar crossref-scitex get 10.1038/nature12373
|
|
22
22
|
scitex scholar crossref-scitex count "epilepsy seizure"
|
|
23
23
|
scitex scholar crossref-scitex info
|
|
24
|
+
|
|
25
|
+
OpenAlex database (284M+ works via openalex-local):
|
|
26
|
+
scitex scholar openalex-scitex search "neural networks"
|
|
27
|
+
scitex scholar openalex-scitex search-by-doi 10.1038/nature12373
|
|
28
|
+
scitex scholar openalex-scitex status
|
|
24
29
|
"""
|
|
25
30
|
|
|
26
31
|
from __future__ import annotations
|
|
@@ -31,6 +36,7 @@ from ._crossref_scitex import crossref_scitex
|
|
|
31
36
|
from ._fetch import fetch
|
|
32
37
|
from ._jobs import jobs
|
|
33
38
|
from ._library import config, library
|
|
39
|
+
from ._openalex_scitex import openalex_scitex
|
|
34
40
|
|
|
35
41
|
|
|
36
42
|
@click.group(
|
|
@@ -40,8 +46,7 @@ from ._library import config, library
|
|
|
40
46
|
@click.option("--help-recursive", is_flag=True, help="Show help for all subcommands")
|
|
41
47
|
@click.pass_context
|
|
42
48
|
def scholar(ctx, help_recursive):
|
|
43
|
-
"""
|
|
44
|
-
Scientific paper management
|
|
49
|
+
r"""Scientific paper management.
|
|
45
50
|
|
|
46
51
|
\b
|
|
47
52
|
Fetch papers, manage your library, and track background jobs.
|
|
@@ -96,8 +101,7 @@ def _print_help_recursive(ctx):
|
|
|
96
101
|
@scholar.group(invoke_without_command=True)
|
|
97
102
|
@click.pass_context
|
|
98
103
|
def mcp(ctx):
|
|
99
|
-
"""
|
|
100
|
-
MCP (Model Context Protocol) server operations
|
|
104
|
+
r"""MCP (Model Context Protocol) server operations.
|
|
101
105
|
|
|
102
106
|
\b
|
|
103
107
|
Commands:
|
|
@@ -124,28 +128,35 @@ def mcp(ctx):
|
|
|
124
128
|
)
|
|
125
129
|
@click.option("--host", default="0.0.0.0", help="Host for HTTP/SSE (default: 0.0.0.0)")
|
|
126
130
|
@click.option(
|
|
127
|
-
"--port", default=
|
|
131
|
+
"--port", default=8085, type=int, help="Port for HTTP/SSE (default: 8085)"
|
|
128
132
|
)
|
|
129
133
|
def start(transport, host, port):
|
|
130
|
-
"""
|
|
131
|
-
|
|
134
|
+
r"""Start the MCP server with scholar tools.
|
|
135
|
+
|
|
136
|
+
\b
|
|
137
|
+
NOTE: This now uses the unified scitex MCP server which includes
|
|
138
|
+
all scholar tools plus other scitex tools (plt, stats, etc.)
|
|
132
139
|
|
|
133
140
|
\b
|
|
134
141
|
Examples:
|
|
135
142
|
scitex scholar mcp start
|
|
136
|
-
scitex scholar mcp start -t http --port
|
|
143
|
+
scitex scholar mcp start -t http --port 8085
|
|
144
|
+
|
|
145
|
+
\b
|
|
146
|
+
Equivalent to: scitex serve -t <transport>
|
|
137
147
|
"""
|
|
138
148
|
import sys
|
|
139
149
|
|
|
140
150
|
try:
|
|
141
|
-
from scitex.
|
|
151
|
+
from scitex.mcp_server import run_server
|
|
142
152
|
|
|
143
153
|
if transport != "stdio":
|
|
144
|
-
click.secho(f"Starting
|
|
154
|
+
click.secho(f"Starting unified scitex MCP server ({transport})", fg="cyan")
|
|
145
155
|
click.echo(f" Host: {host}")
|
|
146
156
|
click.echo(f" Port: {port}")
|
|
157
|
+
click.echo(" Includes: scholar, plt, stats, audio, and more")
|
|
147
158
|
|
|
148
|
-
run_server()
|
|
159
|
+
run_server(transport=transport, host=host, port=port)
|
|
149
160
|
|
|
150
161
|
except ImportError as e:
|
|
151
162
|
click.secho(f"Error: {e}", fg="red", err=True)
|
|
@@ -158,8 +169,7 @@ def start(transport, host, port):
|
|
|
158
169
|
|
|
159
170
|
@mcp.command()
|
|
160
171
|
def doctor():
|
|
161
|
-
"""
|
|
162
|
-
Check MCP server health and dependencies
|
|
172
|
+
r"""Check MCP server health and dependencies.
|
|
163
173
|
|
|
164
174
|
\b
|
|
165
175
|
Example:
|
|
@@ -193,11 +203,18 @@ def doctor():
|
|
|
193
203
|
except ImportError:
|
|
194
204
|
click.secho("NOT INSTALLED (optional)", fg="yellow")
|
|
195
205
|
|
|
206
|
+
click.echo("Checking openalex-local... ", nl=False)
|
|
207
|
+
try:
|
|
208
|
+
import openalex_local # noqa: F401
|
|
209
|
+
|
|
210
|
+
click.secho("OK", fg="green")
|
|
211
|
+
except ImportError:
|
|
212
|
+
click.secho("NOT INSTALLED (optional)", fg="yellow")
|
|
213
|
+
|
|
196
214
|
|
|
197
215
|
@mcp.command("list-tools")
|
|
198
216
|
def list_tools():
|
|
199
|
-
"""
|
|
200
|
-
List available MCP tools
|
|
217
|
+
r"""List available MCP tools.
|
|
201
218
|
|
|
202
219
|
\b
|
|
203
220
|
Example:
|
|
@@ -206,25 +223,35 @@ def list_tools():
|
|
|
206
223
|
click.secho("Scholar MCP Tools", fg="cyan", bold=True)
|
|
207
224
|
click.echo()
|
|
208
225
|
tools = [
|
|
209
|
-
("
|
|
210
|
-
("
|
|
211
|
-
("
|
|
212
|
-
("
|
|
213
|
-
("
|
|
214
|
-
("
|
|
215
|
-
("
|
|
216
|
-
("
|
|
217
|
-
("
|
|
218
|
-
("
|
|
219
|
-
("
|
|
220
|
-
|
|
221
|
-
("
|
|
226
|
+
("search_papers", "Search for papers by query"),
|
|
227
|
+
("resolve_dois", "Resolve DOIs to metadata"),
|
|
228
|
+
("enrich_bibtex", "Enrich BibTeX with abstracts/DOIs"),
|
|
229
|
+
("download_pdf", "Download PDF for a paper"),
|
|
230
|
+
("download_pdfs_batch", "Batch download PDFs"),
|
|
231
|
+
("get_library_status", "Get library status"),
|
|
232
|
+
("parse_bibtex", "Parse BibTeX file"),
|
|
233
|
+
("validate_pdfs", "Validate downloaded PDFs"),
|
|
234
|
+
("authenticate", "Authenticate with institution"),
|
|
235
|
+
("check_auth_status", "Check authentication status"),
|
|
236
|
+
("fetch_papers", "Fetch papers by DOIs (async)"),
|
|
237
|
+
# CrossRef-Local (167M+ papers)
|
|
238
|
+
("crossref_search", "Search CrossRef database (167M+ papers)"),
|
|
239
|
+
("crossref_get", "Get paper by DOI from CrossRef"),
|
|
240
|
+
("crossref_count", "Count papers matching query"),
|
|
241
|
+
("crossref_citations", "Get citation relationships"),
|
|
242
|
+
("crossref_info", "Get CrossRef database status"),
|
|
243
|
+
# OpenAlex-Local (284M+ works)
|
|
244
|
+
("openalex_search", "Search OpenAlex database (284M+ works)"),
|
|
245
|
+
("openalex_get", "Get paper by DOI/ID from OpenAlex"),
|
|
246
|
+
("openalex_count", "Count papers matching query"),
|
|
247
|
+
("openalex_info", "Get OpenAlex database status"),
|
|
222
248
|
]
|
|
223
249
|
for name, desc in tools:
|
|
224
250
|
click.echo(f" {name}: {desc}")
|
|
225
251
|
|
|
226
252
|
|
|
227
253
|
scholar.add_command(crossref_scitex)
|
|
254
|
+
scholar.add_command(openalex_scitex)
|
|
228
255
|
scholar.add_command(fetch)
|
|
229
256
|
scholar.add_command(library)
|
|
230
257
|
scholar.add_command(config)
|
|
@@ -1,142 +1,41 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
# Timestamp: 2026-01-
|
|
2
|
+
# Timestamp: 2026-01-29
|
|
3
3
|
# File: src/scitex/cli/scholar/_crossref_scitex.py
|
|
4
|
-
"""CrossRef-SciTeX CLI
|
|
4
|
+
"""CrossRef-SciTeX CLI - Thin wrapper delegating to crossref-local.
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
This module provides access to the local CrossRef database (167M+ papers)
|
|
7
|
+
by delegating directly to crossref-local CLI without any modifications.
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
from __future__ import annotations
|
|
11
11
|
|
|
12
|
-
import json
|
|
13
12
|
import sys
|
|
14
13
|
|
|
15
14
|
import click
|
|
16
15
|
|
|
17
16
|
|
|
18
|
-
@click.
|
|
19
|
-
|
|
20
|
-
"""
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
\b
|
|
28
|
-
Examples:
|
|
29
|
-
scitex scholar crossref-scitex search "deep learning"
|
|
30
|
-
scitex scholar crossref-scitex get 10.1038/nature12373
|
|
31
|
-
scitex scholar crossref-scitex count "epilepsy seizure"
|
|
32
|
-
scitex scholar crossref-scitex info
|
|
33
|
-
"""
|
|
34
|
-
pass
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
@crossref_scitex.command("search")
|
|
38
|
-
@click.argument("query")
|
|
39
|
-
@click.option("-n", "--limit", default=20, help="Maximum results (default: 20)")
|
|
40
|
-
@click.option("--offset", default=0, help="Skip N results for pagination")
|
|
41
|
-
@click.option("--year-min", type=int, help="Minimum publication year")
|
|
42
|
-
@click.option("--year-max", type=int, help="Maximum publication year")
|
|
43
|
-
@click.option("--enrich", is_flag=True, help="Add citation counts and references")
|
|
44
|
-
@click.option("--json", "as_json", is_flag=True, help="Output as JSON")
|
|
45
|
-
def search_cmd(query, limit, offset, year_min, year_max, enrich, as_json):
|
|
46
|
-
"""
|
|
47
|
-
Search for papers in CrossRef database.
|
|
17
|
+
@click.command(
|
|
18
|
+
"crossref-scitex",
|
|
19
|
+
context_settings={"ignore_unknown_options": True, "allow_extra_args": True},
|
|
20
|
+
)
|
|
21
|
+
@click.option("--help-recursive", is_flag=True, help="Show help for all commands")
|
|
22
|
+
@click.pass_context
|
|
23
|
+
def crossref_scitex(ctx, help_recursive):
|
|
24
|
+
r"""CrossRef-SciTeX database search (167M+ papers).
|
|
48
25
|
|
|
49
26
|
\b
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
scitex scholar crossref search "deep learning" --limit 50
|
|
53
|
-
scitex scholar crossref search "CRISPR" --year-min 2020 --enrich
|
|
54
|
-
"""
|
|
55
|
-
try:
|
|
56
|
-
from scitex.scholar import crossref_scitex as crossref
|
|
57
|
-
except ImportError:
|
|
58
|
-
click.secho(
|
|
59
|
-
"crossref-local not installed. Install with: pip install crossref-local",
|
|
60
|
-
fg="red",
|
|
61
|
-
)
|
|
62
|
-
sys.exit(1)
|
|
63
|
-
|
|
64
|
-
try:
|
|
65
|
-
results = crossref.search(query, limit=limit, offset=offset)
|
|
66
|
-
|
|
67
|
-
if enrich:
|
|
68
|
-
results = crossref.enrich(results)
|
|
69
|
-
|
|
70
|
-
papers = []
|
|
71
|
-
for work in results:
|
|
72
|
-
if year_min and work.year and work.year < year_min:
|
|
73
|
-
continue
|
|
74
|
-
if year_max and work.year and work.year > year_max:
|
|
75
|
-
continue
|
|
76
|
-
papers.append(work)
|
|
77
|
-
if len(papers) >= limit:
|
|
78
|
-
break
|
|
79
|
-
|
|
80
|
-
if as_json:
|
|
81
|
-
output = {
|
|
82
|
-
"query": query,
|
|
83
|
-
"total": results.total,
|
|
84
|
-
"count": len(papers),
|
|
85
|
-
"papers": [
|
|
86
|
-
{
|
|
87
|
-
"doi": p.doi,
|
|
88
|
-
"title": p.title,
|
|
89
|
-
"authors": p.authors,
|
|
90
|
-
"year": p.year,
|
|
91
|
-
"journal": p.journal,
|
|
92
|
-
"citation_count": p.citation_count,
|
|
93
|
-
}
|
|
94
|
-
for p in papers
|
|
95
|
-
],
|
|
96
|
-
}
|
|
97
|
-
click.echo(json.dumps(output, indent=2))
|
|
98
|
-
else:
|
|
99
|
-
click.secho(
|
|
100
|
-
f"Found {results.total} papers for: {query}", fg="green", bold=True
|
|
101
|
-
)
|
|
102
|
-
click.echo()
|
|
103
|
-
|
|
104
|
-
for i, paper in enumerate(papers, 1):
|
|
105
|
-
authors = ", ".join(paper.authors[:3]) if paper.authors else "Unknown"
|
|
106
|
-
if paper.authors and len(paper.authors) > 3:
|
|
107
|
-
authors += " et al."
|
|
108
|
-
|
|
109
|
-
click.secho(f"{i}. {paper.title}", fg="cyan", bold=True)
|
|
110
|
-
click.echo(f" Authors: {authors}")
|
|
111
|
-
click.echo(
|
|
112
|
-
f" Year: {paper.year or 'N/A'} | Journal: {paper.journal or 'N/A'}"
|
|
113
|
-
)
|
|
114
|
-
click.echo(f" DOI: {paper.doi}")
|
|
115
|
-
if paper.citation_count:
|
|
116
|
-
click.echo(f" Citations: {paper.citation_count}")
|
|
117
|
-
click.echo()
|
|
118
|
-
|
|
119
|
-
except Exception as e:
|
|
120
|
-
click.secho(f"Error: {e}", fg="red")
|
|
121
|
-
sys.exit(1)
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
@crossref_scitex.command("get")
|
|
125
|
-
@click.argument("doi")
|
|
126
|
-
@click.option("--citations", is_flag=True, help="Include citing papers")
|
|
127
|
-
@click.option("--references", is_flag=True, help="Include referenced papers")
|
|
128
|
-
@click.option("--json", "as_json", is_flag=True, help="Output as JSON")
|
|
129
|
-
def get_cmd(doi, citations, references, as_json):
|
|
130
|
-
"""
|
|
131
|
-
Get paper details by DOI.
|
|
27
|
+
Thin wrapper for crossref-local. All arguments passed directly.
|
|
28
|
+
Run 'crossref-local --help' for full options.
|
|
132
29
|
|
|
133
30
|
\b
|
|
134
31
|
Examples:
|
|
135
|
-
scitex scholar crossref
|
|
136
|
-
scitex scholar crossref
|
|
32
|
+
scitex scholar crossref-scitex search "deep learning" --abstracts
|
|
33
|
+
scitex scholar crossref-scitex search-by-doi 10.1038/nature12373
|
|
34
|
+
scitex scholar crossref-scitex status
|
|
35
|
+
scitex scholar crossref-scitex cache query "neural networks"
|
|
137
36
|
"""
|
|
138
37
|
try:
|
|
139
|
-
from
|
|
38
|
+
from crossref_local.cli import cli as crossref_cli
|
|
140
39
|
except ImportError:
|
|
141
40
|
click.secho(
|
|
142
41
|
"crossref-local not installed. Install with: pip install crossref-local",
|
|
@@ -144,153 +43,13 @@ def get_cmd(doi, citations, references, as_json):
|
|
|
144
43
|
)
|
|
145
44
|
sys.exit(1)
|
|
146
45
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
click.secho(f"DOI not found: {doi}", fg="red")
|
|
152
|
-
sys.exit(1)
|
|
153
|
-
|
|
154
|
-
if as_json:
|
|
155
|
-
output = {
|
|
156
|
-
"doi": work.doi,
|
|
157
|
-
"title": work.title,
|
|
158
|
-
"authors": work.authors,
|
|
159
|
-
"year": work.year,
|
|
160
|
-
"journal": work.journal,
|
|
161
|
-
"abstract": work.abstract,
|
|
162
|
-
"citation_count": work.citation_count,
|
|
163
|
-
"reference_count": work.reference_count,
|
|
164
|
-
"type": work.type,
|
|
165
|
-
"publisher": work.publisher,
|
|
166
|
-
}
|
|
167
|
-
if citations:
|
|
168
|
-
output["citing_dois"] = crossref.get_citing(doi)
|
|
169
|
-
if references:
|
|
170
|
-
output["referenced_dois"] = crossref.get_cited(doi)
|
|
171
|
-
click.echo(json.dumps(output, indent=2))
|
|
172
|
-
else:
|
|
173
|
-
click.secho(work.title, fg="cyan", bold=True)
|
|
174
|
-
click.echo()
|
|
175
|
-
|
|
176
|
-
if work.authors:
|
|
177
|
-
click.echo(f"Authors: {', '.join(work.authors)}")
|
|
178
|
-
click.echo(f"Year: {work.year or 'N/A'}")
|
|
179
|
-
click.echo(f"Journal: {work.journal or 'N/A'}")
|
|
180
|
-
click.echo(f"DOI: {work.doi}")
|
|
181
|
-
click.echo(f"Type: {work.type or 'N/A'}")
|
|
182
|
-
click.echo(f"Publisher: {work.publisher or 'N/A'}")
|
|
183
|
-
click.echo(f"Citations: {work.citation_count or 0}")
|
|
184
|
-
click.echo(f"References: {work.reference_count or 0}")
|
|
185
|
-
|
|
186
|
-
if work.abstract:
|
|
187
|
-
click.echo()
|
|
188
|
-
click.secho("Abstract:", bold=True)
|
|
189
|
-
click.echo(
|
|
190
|
-
work.abstract[:500] + "..."
|
|
191
|
-
if len(work.abstract) > 500
|
|
192
|
-
else work.abstract
|
|
193
|
-
)
|
|
194
|
-
|
|
195
|
-
if citations:
|
|
196
|
-
citing = crossref.get_citing(doi)
|
|
197
|
-
click.echo()
|
|
198
|
-
click.secho(f"Citing papers ({len(citing)}):", bold=True)
|
|
199
|
-
for c_doi in citing[:10]:
|
|
200
|
-
click.echo(f" - {c_doi}")
|
|
201
|
-
if len(citing) > 10:
|
|
202
|
-
click.echo(f" ... and {len(citing) - 10} more")
|
|
203
|
-
|
|
204
|
-
if references:
|
|
205
|
-
cited = crossref.get_cited(doi)
|
|
206
|
-
click.echo()
|
|
207
|
-
click.secho(f"References ({len(cited)}):", bold=True)
|
|
208
|
-
for r_doi in cited[:10]:
|
|
209
|
-
click.echo(f" - {r_doi}")
|
|
210
|
-
if len(cited) > 10:
|
|
211
|
-
click.echo(f" ... and {len(cited) - 10} more")
|
|
212
|
-
|
|
213
|
-
except Exception as e:
|
|
214
|
-
click.secho(f"Error: {e}", fg="red")
|
|
215
|
-
sys.exit(1)
|
|
46
|
+
# Handle --help-recursive by delegating to crossref-local
|
|
47
|
+
args = ctx.args
|
|
48
|
+
if help_recursive:
|
|
49
|
+
args = ["--help-recursive"]
|
|
216
50
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
@click.argument("query")
|
|
220
|
-
def count_cmd(query):
|
|
221
|
-
"""
|
|
222
|
-
Count papers matching a query.
|
|
223
|
-
|
|
224
|
-
\b
|
|
225
|
-
Examples:
|
|
226
|
-
scitex scholar crossref count "machine learning"
|
|
227
|
-
scitex scholar crossref count "CRISPR gene editing"
|
|
228
|
-
"""
|
|
229
|
-
try:
|
|
230
|
-
from scitex.scholar import crossref_scitex as crossref
|
|
231
|
-
except ImportError:
|
|
232
|
-
click.secho(
|
|
233
|
-
"crossref-local not installed. Install with: pip install crossref-local",
|
|
234
|
-
fg="red",
|
|
235
|
-
)
|
|
236
|
-
sys.exit(1)
|
|
237
|
-
|
|
238
|
-
try:
|
|
239
|
-
count = crossref.count(query)
|
|
240
|
-
click.echo(f"{count:,} papers match: {query}")
|
|
241
|
-
except Exception as e:
|
|
242
|
-
click.secho(f"Error: {e}", fg="red")
|
|
243
|
-
sys.exit(1)
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
@crossref_scitex.command("info")
|
|
247
|
-
@click.option("--json", "as_json", is_flag=True, help="Output as JSON")
|
|
248
|
-
def info_cmd(as_json):
|
|
249
|
-
"""
|
|
250
|
-
Show CrossRef database configuration and status.
|
|
251
|
-
|
|
252
|
-
\b
|
|
253
|
-
Examples:
|
|
254
|
-
scitex scholar crossref info
|
|
255
|
-
scitex scholar crossref info --json
|
|
256
|
-
"""
|
|
257
|
-
try:
|
|
258
|
-
from scitex.scholar import crossref_scitex as crossref
|
|
259
|
-
except ImportError:
|
|
260
|
-
click.secho(
|
|
261
|
-
"crossref-local not installed. Install with: pip install crossref-local",
|
|
262
|
-
fg="red",
|
|
263
|
-
)
|
|
264
|
-
sys.exit(1)
|
|
265
|
-
|
|
266
|
-
try:
|
|
267
|
-
info = crossref.info()
|
|
268
|
-
mode = crossref.get_mode()
|
|
269
|
-
|
|
270
|
-
if as_json:
|
|
271
|
-
info["mode"] = mode
|
|
272
|
-
click.echo(json.dumps(info, indent=2))
|
|
273
|
-
else:
|
|
274
|
-
click.secho("CrossRef Database Status", fg="cyan", bold=True)
|
|
275
|
-
click.echo()
|
|
276
|
-
click.echo(f"Mode: {mode}")
|
|
277
|
-
click.echo(f"Status: {info.get('status', 'unknown')}")
|
|
278
|
-
|
|
279
|
-
if "version" in info:
|
|
280
|
-
click.echo(f"Version: {info['version']}")
|
|
281
|
-
|
|
282
|
-
if "work_count" in info:
|
|
283
|
-
click.echo(f"Papers: {info['work_count']:,}")
|
|
284
|
-
|
|
285
|
-
if "db_path" in info:
|
|
286
|
-
click.echo(f"Database: {info['db_path']}")
|
|
287
|
-
|
|
288
|
-
if "api_url" in info:
|
|
289
|
-
click.echo(f"API URL: {info['api_url']}")
|
|
290
|
-
|
|
291
|
-
except Exception as e:
|
|
292
|
-
click.secho(f"Error: {e}", fg="red")
|
|
293
|
-
sys.exit(1)
|
|
51
|
+
# Delegate all arguments to crossref-local CLI
|
|
52
|
+
sys.exit(crossref_cli.main(args, standalone_mode=False))
|
|
294
53
|
|
|
295
54
|
|
|
296
55
|
# EOF
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# Timestamp: 2026-01-29
|
|
3
|
+
# File: src/scitex/cli/scholar/_openalex_scitex.py
|
|
4
|
+
"""OpenAlex-SciTeX CLI - Thin wrapper delegating to openalex-local.
|
|
5
|
+
|
|
6
|
+
This module provides access to the local OpenAlex database (284M+ works)
|
|
7
|
+
by delegating directly to openalex-local CLI without any modifications.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import sys
|
|
13
|
+
|
|
14
|
+
import click
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@click.command(
|
|
18
|
+
"openalex-scitex",
|
|
19
|
+
context_settings={"ignore_unknown_options": True, "allow_extra_args": True},
|
|
20
|
+
)
|
|
21
|
+
@click.option("--help-recursive", is_flag=True, help="Show help for all commands")
|
|
22
|
+
@click.pass_context
|
|
23
|
+
def openalex_scitex(ctx, help_recursive):
|
|
24
|
+
"""
|
|
25
|
+
OpenAlex-SciTeX database search (284M+ works)
|
|
26
|
+
|
|
27
|
+
\b
|
|
28
|
+
Thin wrapper for openalex-local. All arguments passed directly.
|
|
29
|
+
Run 'openalex-local --help' for full options.
|
|
30
|
+
|
|
31
|
+
\b
|
|
32
|
+
Examples:
|
|
33
|
+
scitex scholar openalex-scitex search "machine learning"
|
|
34
|
+
scitex scholar openalex-scitex search-by-doi 10.1038/nature12373
|
|
35
|
+
scitex scholar openalex-scitex status
|
|
36
|
+
"""
|
|
37
|
+
try:
|
|
38
|
+
from openalex_local.cli import cli as openalex_cli
|
|
39
|
+
except ImportError:
|
|
40
|
+
click.secho(
|
|
41
|
+
"openalex-local not installed. Install with: pip install openalex-local",
|
|
42
|
+
fg="red",
|
|
43
|
+
)
|
|
44
|
+
sys.exit(1)
|
|
45
|
+
|
|
46
|
+
# Handle --help-recursive by delegating to openalex-local
|
|
47
|
+
args = ctx.args
|
|
48
|
+
if help_recursive:
|
|
49
|
+
args = ["--help-recursive"]
|
|
50
|
+
|
|
51
|
+
# Delegate all arguments to openalex-local CLI
|
|
52
|
+
sys.exit(openalex_cli.main(args, standalone_mode=False))
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
# EOF
|
scitex/scholar/__init__.py
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
"""
|
|
2
|
-
SciTeX Scholar - Scientific Literature Management Made Simple
|
|
1
|
+
"""SciTeX Scholar - Scientific Literature Management Made Simple.
|
|
3
2
|
|
|
4
3
|
This module provides a unified interface for:
|
|
5
4
|
- Searching scientific literature across multiple sources
|
|
@@ -27,17 +26,17 @@ _missing = warn_module_deps("scholar")
|
|
|
27
26
|
try:
|
|
28
27
|
from scitex.scholar.auth import ScholarAuthManager
|
|
29
28
|
except ImportError:
|
|
30
|
-
ScholarAuthManager = None
|
|
29
|
+
ScholarAuthManager = None # type: ignore[misc,assignment]
|
|
31
30
|
|
|
32
31
|
try:
|
|
33
32
|
from scitex.scholar.browser import ScholarBrowserManager
|
|
34
33
|
except ImportError:
|
|
35
|
-
ScholarBrowserManager = None
|
|
34
|
+
ScholarBrowserManager = None # type: ignore[misc,assignment]
|
|
36
35
|
|
|
37
36
|
try:
|
|
38
37
|
from scitex.scholar.config import ScholarConfig
|
|
39
38
|
except ImportError:
|
|
40
|
-
ScholarConfig = None
|
|
39
|
+
ScholarConfig = None # type: ignore[misc,assignment]
|
|
41
40
|
|
|
42
41
|
try:
|
|
43
42
|
from scitex.scholar.core import Paper, Papers, Scholar
|
|
@@ -71,12 +70,17 @@ try:
|
|
|
71
70
|
except ImportError:
|
|
72
71
|
utils = None
|
|
73
72
|
|
|
74
|
-
#
|
|
73
|
+
# Local database integrations (crossref-local, openalex-local)
|
|
75
74
|
try:
|
|
76
|
-
from . import crossref_scitex
|
|
75
|
+
from .local_dbs import crossref_scitex
|
|
77
76
|
except ImportError:
|
|
78
77
|
crossref_scitex = None
|
|
79
78
|
|
|
79
|
+
try:
|
|
80
|
+
from .local_dbs import openalex_scitex
|
|
81
|
+
except ImportError:
|
|
82
|
+
openalex_scitex = None
|
|
83
|
+
|
|
80
84
|
__all__ = [
|
|
81
85
|
"ScholarConfig",
|
|
82
86
|
"ScholarEngine",
|
|
@@ -87,8 +91,9 @@ __all__ = [
|
|
|
87
91
|
"Papers",
|
|
88
92
|
"Scholar",
|
|
89
93
|
"utils",
|
|
90
|
-
#
|
|
91
|
-
"crossref_scitex",
|
|
94
|
+
# Local database integrations
|
|
95
|
+
"crossref_scitex", # CrossRef (167M+ papers via crossref-local)
|
|
96
|
+
"openalex_scitex", # OpenAlex (284M+ works via openalex-local)
|
|
92
97
|
]
|
|
93
98
|
|
|
94
99
|
# # Import core classes for advanced users
|