scitex 2.14.0__py3-none-any.whl → 2.15.1__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/__init__.py +47 -0
- scitex/_env_loader.py +156 -0
- scitex/_mcp_resources/__init__.py +37 -0
- scitex/_mcp_resources/_cheatsheet.py +135 -0
- scitex/_mcp_resources/_figrecipe.py +138 -0
- scitex/_mcp_resources/_formats.py +102 -0
- scitex/_mcp_resources/_modules.py +337 -0
- scitex/_mcp_resources/_session.py +149 -0
- scitex/_mcp_tools/__init__.py +4 -0
- scitex/_mcp_tools/audio.py +66 -0
- scitex/_mcp_tools/diagram.py +11 -95
- scitex/_mcp_tools/introspect.py +191 -0
- scitex/_mcp_tools/plt.py +260 -305
- scitex/_mcp_tools/scholar.py +74 -0
- scitex/_mcp_tools/social.py +244 -0
- scitex/_mcp_tools/writer.py +21 -204
- scitex/ai/_gen_ai/_PARAMS.py +10 -7
- scitex/ai/classification/reporters/_SingleClassificationReporter.py +45 -1603
- scitex/ai/classification/reporters/_mixins/__init__.py +36 -0
- scitex/ai/classification/reporters/_mixins/_constants.py +67 -0
- scitex/ai/classification/reporters/_mixins/_cv_summary.py +387 -0
- scitex/ai/classification/reporters/_mixins/_feature_importance.py +119 -0
- scitex/ai/classification/reporters/_mixins/_metrics.py +275 -0
- scitex/ai/classification/reporters/_mixins/_plotting.py +179 -0
- scitex/ai/classification/reporters/_mixins/_reports.py +153 -0
- scitex/ai/classification/reporters/_mixins/_storage.py +160 -0
- scitex/audio/README.md +40 -36
- scitex/audio/__init__.py +127 -59
- scitex/audio/_branding.py +185 -0
- scitex/audio/_mcp/__init__.py +32 -0
- scitex/audio/_mcp/handlers.py +59 -6
- scitex/audio/_mcp/speak_handlers.py +238 -0
- scitex/audio/_relay.py +225 -0
- scitex/audio/engines/elevenlabs_engine.py +6 -1
- scitex/audio/mcp_server.py +228 -75
- scitex/canvas/README.md +1 -1
- scitex/canvas/editor/_dearpygui/__init__.py +25 -0
- scitex/canvas/editor/_dearpygui/_editor.py +147 -0
- scitex/canvas/editor/_dearpygui/_handlers.py +476 -0
- scitex/canvas/editor/_dearpygui/_panels/__init__.py +17 -0
- scitex/canvas/editor/_dearpygui/_panels/_control.py +119 -0
- scitex/canvas/editor/_dearpygui/_panels/_element_controls.py +190 -0
- scitex/canvas/editor/_dearpygui/_panels/_preview.py +43 -0
- scitex/canvas/editor/_dearpygui/_panels/_sections.py +390 -0
- scitex/canvas/editor/_dearpygui/_plotting.py +187 -0
- scitex/canvas/editor/_dearpygui/_rendering.py +504 -0
- scitex/canvas/editor/_dearpygui/_selection.py +295 -0
- scitex/canvas/editor/_dearpygui/_state.py +93 -0
- scitex/canvas/editor/_dearpygui/_utils.py +61 -0
- scitex/canvas/editor/flask_editor/templates/__init__.py +32 -70
- scitex/cli/__init__.py +38 -43
- scitex/cli/audio.py +76 -27
- scitex/cli/capture.py +13 -20
- scitex/cli/introspect.py +443 -0
- scitex/cli/main.py +198 -109
- scitex/cli/mcp.py +60 -34
- scitex/cli/scholar/__init__.py +8 -0
- scitex/cli/scholar/_crossref_scitex.py +296 -0
- scitex/cli/scholar/_fetch.py +25 -3
- scitex/cli/social.py +314 -0
- scitex/cli/writer.py +117 -0
- scitex/config/README.md +1 -1
- scitex/config/__init__.py +16 -2
- scitex/config/_env_registry.py +191 -0
- scitex/diagram/__init__.py +42 -19
- scitex/diagram/mcp_server.py +13 -125
- scitex/introspect/__init__.py +75 -0
- scitex/introspect/_call_graph.py +303 -0
- scitex/introspect/_class_hierarchy.py +163 -0
- scitex/introspect/_core.py +42 -0
- scitex/introspect/_docstring.py +131 -0
- scitex/introspect/_examples.py +113 -0
- scitex/introspect/_imports.py +271 -0
- scitex/introspect/_mcp/__init__.py +37 -0
- scitex/introspect/_mcp/handlers.py +208 -0
- scitex/introspect/_members.py +151 -0
- scitex/introspect/_resolve.py +89 -0
- scitex/introspect/_signature.py +131 -0
- scitex/introspect/_source.py +80 -0
- scitex/introspect/_type_hints.py +172 -0
- scitex/io/bundle/README.md +1 -1
- scitex/mcp_server.py +98 -5
- scitex/plt/__init__.py +248 -550
- scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin/_wrappers.py +5 -10
- scitex/plt/docs/EXTERNAL_PACKAGE_BRANDING.md +149 -0
- scitex/plt/gallery/README.md +1 -1
- scitex/plt/utils/_hitmap/__init__.py +82 -0
- scitex/plt/utils/_hitmap/_artist_extraction.py +343 -0
- scitex/plt/utils/_hitmap/_color_application.py +346 -0
- scitex/plt/utils/_hitmap/_color_conversion.py +121 -0
- scitex/plt/utils/_hitmap/_constants.py +40 -0
- scitex/plt/utils/_hitmap/_hitmap_core.py +334 -0
- scitex/plt/utils/_hitmap/_path_extraction.py +357 -0
- scitex/plt/utils/_hitmap/_query.py +113 -0
- scitex/plt/utils/_hitmap.py +46 -1616
- scitex/plt/utils/_metadata/__init__.py +80 -0
- scitex/plt/utils/_metadata/_artists/__init__.py +25 -0
- scitex/plt/utils/_metadata/_artists/_base.py +195 -0
- scitex/plt/utils/_metadata/_artists/_collections.py +356 -0
- scitex/plt/utils/_metadata/_artists/_extract.py +57 -0
- scitex/plt/utils/_metadata/_artists/_images.py +80 -0
- scitex/plt/utils/_metadata/_artists/_lines.py +261 -0
- scitex/plt/utils/_metadata/_artists/_patches.py +247 -0
- scitex/plt/utils/_metadata/_artists/_text.py +106 -0
- scitex/plt/utils/_metadata/_csv.py +416 -0
- scitex/plt/utils/_metadata/_detect.py +225 -0
- scitex/plt/utils/_metadata/_legend.py +127 -0
- scitex/plt/utils/_metadata/_rounding.py +117 -0
- scitex/plt/utils/_metadata/_verification.py +202 -0
- scitex/schema/README.md +1 -1
- scitex/scholar/__init__.py +8 -0
- scitex/scholar/_mcp/crossref_handlers.py +265 -0
- scitex/scholar/core/Scholar.py +63 -1700
- scitex/scholar/core/_mixins/__init__.py +36 -0
- scitex/scholar/core/_mixins/_enrichers.py +270 -0
- scitex/scholar/core/_mixins/_library_handlers.py +100 -0
- scitex/scholar/core/_mixins/_loaders.py +103 -0
- scitex/scholar/core/_mixins/_pdf_download.py +375 -0
- scitex/scholar/core/_mixins/_pipeline.py +312 -0
- scitex/scholar/core/_mixins/_project_handlers.py +125 -0
- scitex/scholar/core/_mixins/_savers.py +69 -0
- scitex/scholar/core/_mixins/_search.py +103 -0
- scitex/scholar/core/_mixins/_services.py +88 -0
- scitex/scholar/core/_mixins/_url_finding.py +105 -0
- scitex/scholar/crossref_scitex.py +367 -0
- scitex/scholar/docs/EXTERNAL_PACKAGE_BRANDING.md +149 -0
- scitex/scholar/examples/00_run_all.sh +120 -0
- scitex/scholar/jobs/_executors.py +27 -3
- scitex/scholar/pdf_download/ScholarPDFDownloader.py +38 -416
- scitex/scholar/pdf_download/_cli.py +154 -0
- scitex/scholar/pdf_download/strategies/__init__.py +11 -8
- scitex/scholar/pdf_download/strategies/manual_download_fallback.py +80 -3
- scitex/scholar/pipelines/ScholarPipelineBibTeX.py +73 -121
- scitex/scholar/pipelines/ScholarPipelineParallel.py +80 -138
- scitex/scholar/pipelines/ScholarPipelineSingle.py +43 -63
- scitex/scholar/pipelines/_single_steps.py +71 -36
- scitex/scholar/storage/_LibraryManager.py +97 -1695
- scitex/scholar/storage/_mixins/__init__.py +30 -0
- scitex/scholar/storage/_mixins/_bibtex_handlers.py +128 -0
- scitex/scholar/storage/_mixins/_library_operations.py +218 -0
- scitex/scholar/storage/_mixins/_metadata_conversion.py +226 -0
- scitex/scholar/storage/_mixins/_paper_saving.py +456 -0
- scitex/scholar/storage/_mixins/_resolution.py +376 -0
- scitex/scholar/storage/_mixins/_storage_helpers.py +121 -0
- scitex/scholar/storage/_mixins/_symlink_handlers.py +226 -0
- scitex/scholar/url_finder/.tmp/open_url/KNOWN_RESOLVERS.py +462 -0
- scitex/scholar/url_finder/.tmp/open_url/README.md +223 -0
- scitex/scholar/url_finder/.tmp/open_url/_DOIToURLResolver.py +694 -0
- scitex/scholar/url_finder/.tmp/open_url/_OpenURLResolver.py +1160 -0
- scitex/scholar/url_finder/.tmp/open_url/_ResolverLinkFinder.py +344 -0
- scitex/scholar/url_finder/.tmp/open_url/__init__.py +24 -0
- scitex/security/README.md +3 -3
- scitex/session/README.md +1 -1
- scitex/sh/README.md +1 -1
- scitex/social/__init__.py +153 -0
- scitex/social/docs/EXTERNAL_PACKAGE_BRANDING.md +149 -0
- scitex/template/README.md +1 -1
- scitex/template/clone_writer_directory.py +5 -5
- scitex/writer/README.md +1 -1
- scitex/writer/_mcp/handlers.py +11 -744
- scitex/writer/_mcp/tool_schemas.py +5 -335
- scitex-2.15.1.dist-info/METADATA +648 -0
- {scitex-2.14.0.dist-info → scitex-2.15.1.dist-info}/RECORD +166 -111
- scitex/canvas/editor/flask_editor/templates/_scripts.py +0 -4933
- scitex/canvas/editor/flask_editor/templates/_styles.py +0 -1658
- scitex/dev/plt/data/mpl/PLOTTING_FUNCTIONS.yaml +0 -90
- scitex/dev/plt/data/mpl/PLOTTING_SIGNATURES.yaml +0 -1571
- scitex/dev/plt/data/mpl/PLOTTING_SIGNATURES_DETAILED.yaml +0 -6262
- scitex/dev/plt/data/mpl/SIGNATURES_FLATTENED.yaml +0 -1274
- scitex/dev/plt/data/mpl/dir_ax.txt +0 -459
- scitex/diagram/_compile.py +0 -312
- scitex/diagram/_diagram.py +0 -355
- scitex/diagram/_mcp/__init__.py +0 -4
- scitex/diagram/_mcp/handlers.py +0 -400
- scitex/diagram/_mcp/tool_schemas.py +0 -157
- scitex/diagram/_presets.py +0 -173
- scitex/diagram/_schema.py +0 -182
- scitex/diagram/_split.py +0 -278
- scitex/plt/_mcp/__init__.py +0 -4
- scitex/plt/_mcp/_handlers_annotation.py +0 -102
- scitex/plt/_mcp/_handlers_figure.py +0 -195
- scitex/plt/_mcp/_handlers_plot.py +0 -252
- scitex/plt/_mcp/_handlers_style.py +0 -219
- scitex/plt/_mcp/handlers.py +0 -74
- scitex/plt/_mcp/tool_schemas.py +0 -497
- scitex/plt/mcp_server.py +0 -231
- scitex/scholar/data/.gitkeep +0 -0
- scitex/scholar/data/README.md +0 -44
- scitex/scholar/data/bib_files/bibliography.bib +0 -1952
- scitex/scholar/data/bib_files/neurovista.bib +0 -277
- scitex/scholar/data/bib_files/neurovista_enriched.bib +0 -441
- scitex/scholar/data/bib_files/neurovista_enriched_enriched.bib +0 -441
- scitex/scholar/data/bib_files/neurovista_processed.bib +0 -338
- scitex/scholar/data/bib_files/openaccess.bib +0 -89
- scitex/scholar/data/bib_files/pac-seizure_prediction_enriched.bib +0 -2178
- scitex/scholar/data/bib_files/pac.bib +0 -698
- scitex/scholar/data/bib_files/pac_enriched.bib +0 -1061
- scitex/scholar/data/bib_files/pac_processed.bib +0 -0
- scitex/scholar/data/bib_files/pac_titles.txt +0 -75
- scitex/scholar/data/bib_files/paywalled.bib +0 -98
- scitex/scholar/data/bib_files/related-papers-by-coauthors.bib +0 -58
- scitex/scholar/data/bib_files/related-papers-by-coauthors_enriched.bib +0 -87
- scitex/scholar/data/bib_files/seizure_prediction.bib +0 -694
- scitex/scholar/data/bib_files/seizure_prediction_processed.bib +0 -0
- scitex/scholar/data/bib_files/test_complete_enriched.bib +0 -437
- scitex/scholar/data/bib_files/test_final_enriched.bib +0 -437
- scitex/scholar/data/bib_files/test_seizure.bib +0 -46
- scitex/scholar/data/impact_factor/JCR_IF_2022.xlsx +0 -0
- scitex/scholar/data/impact_factor/JCR_IF_2024.db +0 -0
- scitex/scholar/data/impact_factor/JCR_IF_2024.xlsx +0 -0
- scitex/scholar/data/impact_factor/JCR_IF_2024_v01.db +0 -0
- scitex/scholar/data/impact_factor.db +0 -0
- scitex/scholar/examples/SUGGESTIONS.md +0 -865
- scitex/scholar/examples/dev.py +0 -38
- scitex-2.14.0.dist-info/METADATA +0 -1238
- {scitex-2.14.0.dist-info → scitex-2.15.1.dist-info}/WHEEL +0 -0
- {scitex-2.14.0.dist-info → scitex-2.15.1.dist-info}/entry_points.txt +0 -0
- {scitex-2.14.0.dist-info → scitex-2.15.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# Timestamp: 2026-01-24
|
|
3
|
+
# File: src/scitex/scholar/_mcp/crossref_handlers.py
|
|
4
|
+
"""CrossRef-SciTeX handler implementations via crossref-local delegation.
|
|
5
|
+
|
|
6
|
+
These handlers delegate to crossref-local for fast access to 167M+ papers.
|
|
7
|
+
Branded as crossref-scitex to distinguish from official CrossRef API.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import asyncio
|
|
13
|
+
from datetime import datetime
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
"crossref_search_handler",
|
|
17
|
+
"crossref_get_handler",
|
|
18
|
+
"crossref_count_handler",
|
|
19
|
+
"crossref_citations_handler",
|
|
20
|
+
"crossref_info_handler",
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _ensure_crossref():
|
|
25
|
+
"""Ensure crossref_scitex module is available."""
|
|
26
|
+
try:
|
|
27
|
+
from scitex.scholar import crossref_scitex
|
|
28
|
+
|
|
29
|
+
return crossref_scitex
|
|
30
|
+
except ImportError as e:
|
|
31
|
+
raise RuntimeError(
|
|
32
|
+
"crossref-local not installed. Install with: pip install crossref-local"
|
|
33
|
+
) from e
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
async def crossref_search_handler(
|
|
37
|
+
query: str,
|
|
38
|
+
limit: int = 20,
|
|
39
|
+
offset: int = 0,
|
|
40
|
+
year_min: int | None = None,
|
|
41
|
+
year_max: int | None = None,
|
|
42
|
+
enrich: bool = False,
|
|
43
|
+
) -> dict:
|
|
44
|
+
"""Search CrossRef database (167M+ papers) via crossref-local.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
query: Search query string (full-text search)
|
|
48
|
+
limit: Maximum number of results (default: 20)
|
|
49
|
+
offset: Number of results to skip for pagination
|
|
50
|
+
year_min: Minimum publication year filter
|
|
51
|
+
year_max: Maximum publication year filter
|
|
52
|
+
enrich: If True, add citation counts and references
|
|
53
|
+
"""
|
|
54
|
+
try:
|
|
55
|
+
crossref = _ensure_crossref()
|
|
56
|
+
loop = asyncio.get_running_loop()
|
|
57
|
+
|
|
58
|
+
def do_search():
|
|
59
|
+
# Fetch more results for filtering
|
|
60
|
+
fetch_limit = limit * 2 if (year_min or year_max) else limit
|
|
61
|
+
results = crossref.search(query, limit=fetch_limit, offset=offset)
|
|
62
|
+
|
|
63
|
+
if enrich:
|
|
64
|
+
results = crossref.enrich(results)
|
|
65
|
+
|
|
66
|
+
papers = []
|
|
67
|
+
for work in results:
|
|
68
|
+
# Apply year filters
|
|
69
|
+
if year_min and work.year and work.year < year_min:
|
|
70
|
+
continue
|
|
71
|
+
if year_max and work.year and work.year > year_max:
|
|
72
|
+
continue
|
|
73
|
+
|
|
74
|
+
papers.append(
|
|
75
|
+
{
|
|
76
|
+
"doi": work.doi,
|
|
77
|
+
"title": work.title,
|
|
78
|
+
"authors": work.authors[:10] if work.authors else [],
|
|
79
|
+
"year": work.year,
|
|
80
|
+
"journal": work.journal,
|
|
81
|
+
"abstract": (
|
|
82
|
+
work.abstract[:500] + "..."
|
|
83
|
+
if work.abstract and len(work.abstract) > 500
|
|
84
|
+
else work.abstract
|
|
85
|
+
),
|
|
86
|
+
"citation_count": work.citation_count,
|
|
87
|
+
"reference_count": work.reference_count,
|
|
88
|
+
"type": work.type,
|
|
89
|
+
}
|
|
90
|
+
)
|
|
91
|
+
if len(papers) >= limit:
|
|
92
|
+
break
|
|
93
|
+
|
|
94
|
+
return papers, results.total
|
|
95
|
+
|
|
96
|
+
papers, total = await loop.run_in_executor(None, do_search)
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
"success": True,
|
|
100
|
+
"query": query,
|
|
101
|
+
"total": total,
|
|
102
|
+
"count": len(papers),
|
|
103
|
+
"offset": offset,
|
|
104
|
+
"limit": limit,
|
|
105
|
+
"papers": papers,
|
|
106
|
+
"source": "crossref_local",
|
|
107
|
+
"timestamp": datetime.now().isoformat(),
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
except Exception as e:
|
|
111
|
+
return {"success": False, "error": str(e)}
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
async def crossref_get_handler(
|
|
115
|
+
doi: str,
|
|
116
|
+
include_citations: bool = False,
|
|
117
|
+
include_references: bool = False,
|
|
118
|
+
) -> dict:
|
|
119
|
+
"""Get a paper by DOI from CrossRef database.
|
|
120
|
+
|
|
121
|
+
Args:
|
|
122
|
+
doi: DOI of the paper
|
|
123
|
+
include_citations: Include list of citing DOIs
|
|
124
|
+
include_references: Include list of referenced DOIs
|
|
125
|
+
"""
|
|
126
|
+
try:
|
|
127
|
+
crossref = _ensure_crossref()
|
|
128
|
+
loop = asyncio.get_running_loop()
|
|
129
|
+
|
|
130
|
+
def do_get():
|
|
131
|
+
work = crossref.get(doi)
|
|
132
|
+
if not work:
|
|
133
|
+
return None
|
|
134
|
+
|
|
135
|
+
result = {
|
|
136
|
+
"doi": work.doi,
|
|
137
|
+
"title": work.title,
|
|
138
|
+
"authors": work.authors,
|
|
139
|
+
"year": work.year,
|
|
140
|
+
"journal": work.journal,
|
|
141
|
+
"abstract": work.abstract,
|
|
142
|
+
"citation_count": work.citation_count,
|
|
143
|
+
"reference_count": work.reference_count,
|
|
144
|
+
"type": work.type,
|
|
145
|
+
"publisher": work.publisher,
|
|
146
|
+
"url": work.url,
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if include_citations:
|
|
150
|
+
result["citing_dois"] = crossref.get_citing(doi)
|
|
151
|
+
|
|
152
|
+
if include_references:
|
|
153
|
+
result["referenced_dois"] = crossref.get_cited(doi)
|
|
154
|
+
|
|
155
|
+
return result
|
|
156
|
+
|
|
157
|
+
result = await loop.run_in_executor(None, do_get)
|
|
158
|
+
|
|
159
|
+
if result is None:
|
|
160
|
+
return {
|
|
161
|
+
"success": False,
|
|
162
|
+
"error": f"DOI not found: {doi}",
|
|
163
|
+
"doi": doi,
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return {
|
|
167
|
+
"success": True,
|
|
168
|
+
"paper": result,
|
|
169
|
+
"source": "crossref_local",
|
|
170
|
+
"timestamp": datetime.now().isoformat(),
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
except Exception as e:
|
|
174
|
+
return {"success": False, "error": str(e)}
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
async def crossref_count_handler(query: str) -> dict:
|
|
178
|
+
"""Count papers matching a search query.
|
|
179
|
+
|
|
180
|
+
Args:
|
|
181
|
+
query: Search query string
|
|
182
|
+
"""
|
|
183
|
+
try:
|
|
184
|
+
crossref = _ensure_crossref()
|
|
185
|
+
loop = asyncio.get_running_loop()
|
|
186
|
+
|
|
187
|
+
count = await loop.run_in_executor(None, crossref.count, query)
|
|
188
|
+
|
|
189
|
+
return {
|
|
190
|
+
"success": True,
|
|
191
|
+
"query": query,
|
|
192
|
+
"count": count,
|
|
193
|
+
"source": "crossref_local",
|
|
194
|
+
"timestamp": datetime.now().isoformat(),
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
except Exception as e:
|
|
198
|
+
return {"success": False, "error": str(e)}
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
async def crossref_citations_handler(
|
|
202
|
+
doi: str,
|
|
203
|
+
direction: str = "citing", # "citing", "cited", or "both"
|
|
204
|
+
limit: int = 100,
|
|
205
|
+
) -> dict:
|
|
206
|
+
"""Get citation relationships for a paper.
|
|
207
|
+
|
|
208
|
+
Args:
|
|
209
|
+
doi: DOI of the paper
|
|
210
|
+
direction: "citing" (papers that cite this), "cited" (references), or "both"
|
|
211
|
+
limit: Maximum number of results per direction
|
|
212
|
+
"""
|
|
213
|
+
try:
|
|
214
|
+
crossref = _ensure_crossref()
|
|
215
|
+
loop = asyncio.get_running_loop()
|
|
216
|
+
|
|
217
|
+
def do_citations():
|
|
218
|
+
result = {"doi": doi}
|
|
219
|
+
|
|
220
|
+
if direction in ("citing", "both"):
|
|
221
|
+
citing = crossref.get_citing(doi)
|
|
222
|
+
result["citing_dois"] = citing[:limit]
|
|
223
|
+
result["citing_count"] = len(citing)
|
|
224
|
+
|
|
225
|
+
if direction in ("cited", "both"):
|
|
226
|
+
cited = crossref.get_cited(doi)
|
|
227
|
+
result["cited_dois"] = cited[:limit]
|
|
228
|
+
result["cited_count"] = len(cited)
|
|
229
|
+
|
|
230
|
+
return result
|
|
231
|
+
|
|
232
|
+
result = await loop.run_in_executor(None, do_citations)
|
|
233
|
+
|
|
234
|
+
return {
|
|
235
|
+
"success": True,
|
|
236
|
+
**result,
|
|
237
|
+
"direction": direction,
|
|
238
|
+
"source": "crossref_local",
|
|
239
|
+
"timestamp": datetime.now().isoformat(),
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
except Exception as e:
|
|
243
|
+
return {"success": False, "error": str(e)}
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
async def crossref_info_handler() -> dict:
|
|
247
|
+
"""Get information about CrossRef database configuration and status."""
|
|
248
|
+
try:
|
|
249
|
+
crossref = _ensure_crossref()
|
|
250
|
+
loop = asyncio.get_running_loop()
|
|
251
|
+
|
|
252
|
+
info = await loop.run_in_executor(None, crossref.info)
|
|
253
|
+
|
|
254
|
+
return {
|
|
255
|
+
"success": True,
|
|
256
|
+
"info": info,
|
|
257
|
+
"mode": crossref.get_mode(),
|
|
258
|
+
"timestamp": datetime.now().isoformat(),
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
except Exception as e:
|
|
262
|
+
return {"success": False, "error": str(e)}
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
# EOF
|