crossref-local 0.3.0__tar.gz → 0.3.1__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.
Files changed (136) hide show
  1. {crossref_local-0.3.0 → crossref_local-0.3.1}/.github/workflows/test.yml +1 -1
  2. {crossref_local-0.3.0 → crossref_local-0.3.1}/.gitignore +1 -0
  3. {crossref_local-0.3.0 → crossref_local-0.3.1}/CHANGELOG.md +19 -0
  4. {crossref_local-0.3.0 → crossref_local-0.3.1}/Makefile +16 -1
  5. {crossref_local-0.3.0 → crossref_local-0.3.1}/PKG-INFO +111 -5
  6. {crossref_local-0.3.0 → crossref_local-0.3.1}/README.md +94 -4
  7. {crossref_local-0.3.0 → crossref_local-0.3.1}/pyproject.toml +14 -1
  8. crossref_local-0.3.1/scripts/README.md +132 -0
  9. crossref_local-0.3.1/scripts/database/02_create_missing_indexes.sh +100 -0
  10. crossref_local-0.3.1/scripts/database/06_calculate_abstract_ratio.py +166 -0
  11. {crossref_local-0.3.0 → crossref_local-0.3.1}/scripts/database/99_maintain_indexes.sh +52 -11
  12. {crossref_local-0.3.0 → crossref_local-0.3.1}/scripts/database/99_switch_to_optimized.sh +41 -2
  13. crossref_local-0.3.1/scripts/deployment/build_apptainer.sh +105 -0
  14. crossref_local-0.3.1/scripts/deployment/install_apptainer.sh +105 -0
  15. crossref_local-0.3.1/scripts/deployment/run_apptainer.sh +109 -0
  16. crossref_local-0.3.1/scripts/deployment/run_docker.sh +126 -0
  17. crossref_local-0.3.1/scripts/nfs/check.sh +21 -0
  18. crossref_local-0.3.1/scripts/nfs/setup_nfs.sh +161 -0
  19. crossref_local-0.3.1/scripts/nfs/status.sh +27 -0
  20. crossref_local-0.3.1/scripts/nfs/stop.sh +22 -0
  21. crossref_local-0.3.1/src/crossref_local/__init__.py +128 -0
  22. crossref_local-0.3.1/src/crossref_local/__main__.py +6 -0
  23. {crossref_local-0.3.0 → crossref_local-0.3.1}/src/crossref_local/api.py +73 -5
  24. crossref_local-0.3.1/src/crossref_local/cli.py +450 -0
  25. crossref_local-0.3.1/src/crossref_local/config.py +171 -0
  26. {crossref_local-0.3.0 → crossref_local-0.3.1}/src/crossref_local/db.py +3 -1
  27. {crossref_local-0.3.0 → crossref_local-0.3.1}/src/crossref_local/fts.py +38 -4
  28. crossref_local-0.3.1/src/crossref_local/mcp_server.py +202 -0
  29. crossref_local-0.3.1/src/crossref_local/remote.py +264 -0
  30. crossref_local-0.3.1/src/crossref_local/server.py +352 -0
  31. crossref_local-0.3.1/tests/crossref_local/test_aio.py +227 -0
  32. crossref_local-0.3.1/tests/crossref_local/test_citations.py +250 -0
  33. crossref_local-0.3.1/tests/crossref_local/test_cli.py +183 -0
  34. crossref_local-0.3.1/tests/crossref_local/test_config.py +114 -0
  35. crossref_local-0.3.1/tests/crossref_local/test_db.py +138 -0
  36. crossref_local-0.3.1/tests/crossref_local/test_fts.py +147 -0
  37. crossref_local-0.3.1/tests/crossref_local/test_mcp_server.py +98 -0
  38. crossref_local-0.3.1/tests/crossref_local/test_remote.py +323 -0
  39. crossref_local-0.3.1/tests/crossref_local/test_server.py +169 -0
  40. crossref_local-0.3.0/scripts/README.md +0 -153
  41. crossref_local-0.3.0/scripts/database/02_create_missing_indexes.sh +0 -43
  42. crossref_local-0.3.0/scripts/deployment/build_apptainer.sh +0 -68
  43. crossref_local-0.3.0/scripts/deployment/install_apptainer.sh +0 -87
  44. crossref_local-0.3.0/scripts/deployment/run_apptainer.sh +0 -36
  45. crossref_local-0.3.0/scripts/deployment/run_docker.sh +0 -20
  46. crossref_local-0.3.0/src/crossref_local/__init__.py +0 -78
  47. crossref_local-0.3.0/src/crossref_local/cli.py +0 -257
  48. crossref_local-0.3.0/src/crossref_local/config.py +0 -72
  49. crossref_local-0.3.0/tests/crossref_local/test_cli.py +0 -190
  50. crossref_local-0.3.0/tests/crossref_local/test_config.py +0 -87
  51. crossref_local-0.3.0/tests/crossref_local/test_db.py +0 -151
  52. crossref_local-0.3.0/tests/crossref_local/test_fts.py +0 -142
  53. {crossref_local-0.3.0 → crossref_local-0.3.1}/.env.example +0 -0
  54. {crossref_local-0.3.0 → crossref_local-0.3.1}/.old/impact_factor_standalone_20260110/docs/to_claude/examples/example-python-project-scitex/data/.gitkeep +0 -0
  55. {crossref_local-0.3.0 → crossref_local-0.3.1}/docs/to_claude/examples/example-python-project-scitex/data/.gitkeep +0 -0
  56. {crossref_local-0.3.0 → crossref_local-0.3.1}/examples/citation_network/citation_network.html +0 -0
  57. {crossref_local-0.3.0 → crossref_local-0.3.1}/examples/citation_network/citation_network.yaml +0 -0
  58. {crossref_local-0.3.0 → crossref_local-0.3.1}/examples/citation_network/generate_visualization.py +0 -0
  59. {crossref_local-0.3.0 → crossref_local-0.3.1}/examples/compose_readme.py +0 -0
  60. {crossref_local-0.3.0 → crossref_local-0.3.1}/examples/impact_factor/00_calculate_impact_factor.py +0 -0
  61. {crossref_local-0.3.0 → crossref_local-0.3.1}/examples/impact_factor/01_compare_jcr.py +0 -0
  62. {crossref_local-0.3.0 → crossref_local-0.3.1}/examples/impact_factor/01_compare_jcr_out/all_combined.json +0 -0
  63. {crossref_local-0.3.0 → crossref_local-0.3.1}/examples/impact_factor/01_compare_jcr_out/biomedical_engineering.json +0 -0
  64. {crossref_local-0.3.0 → crossref_local-0.3.1}/examples/impact_factor/01_compare_jcr_out/high_impact.json +0 -0
  65. {crossref_local-0.3.0 → crossref_local-0.3.1}/examples/impact_factor/01_compare_jcr_out/neuroscience.json +0 -0
  66. {crossref_local-0.3.0 → crossref_local-0.3.1}/examples/impact_factor/02_compare_jcr_plot.py +0 -0
  67. {crossref_local-0.3.0 → crossref_local-0.3.1}/examples/impact_factor/02_compare_jcr_plot_out/scatter_calc_vs_jcr.yaml +0 -0
  68. {crossref_local-0.3.0 → crossref_local-0.3.1}/examples/impact_factor/run_all_demos.sh +0 -0
  69. {crossref_local-0.3.0 → crossref_local-0.3.1}/examples/quickstart.py +0 -0
  70. {crossref_local-0.3.0 → crossref_local-0.3.1}/examples/readme_figure.yaml +0 -0
  71. {crossref_local-0.3.0 → crossref_local-0.3.1}/scripts/create_test_db.py +0 -0
  72. {crossref_local-0.3.0 → crossref_local-0.3.1}/scripts/database/00_rebuild_all.sh +0 -0
  73. {crossref_local-0.3.0 → crossref_local-0.3.1}/scripts/database/03_rebuild_citations_table.py +0 -0
  74. {crossref_local-0.3.0 → crossref_local-0.3.1}/scripts/database/03_rebuild_citations_table_optimized.py +0 -0
  75. {crossref_local-0.3.0 → crossref_local-0.3.1}/scripts/database/04a_download_openalex_journals.py +0 -0
  76. {crossref_local-0.3.0 → crossref_local-0.3.1}/scripts/database/04b_build_issn_table.py +0 -0
  77. {crossref_local-0.3.0 → crossref_local-0.3.1}/scripts/database/04c_build_journals_table.py +0 -0
  78. {crossref_local-0.3.0 → crossref_local-0.3.1}/scripts/database/04d_build_from_issn_list.py +0 -0
  79. {crossref_local-0.3.0 → crossref_local-0.3.1}/scripts/database/05_build_fts5_index.py +0 -0
  80. {crossref_local-0.3.0 → crossref_local-0.3.1}/scripts/database/99_check_db_connections.py +0 -0
  81. {crossref_local-0.3.0 → crossref_local-0.3.1}/scripts/database/99_db_info.sh +0 -0
  82. {crossref_local-0.3.0 → crossref_local-0.3.1}/scripts/database/README.md +0 -0
  83. {crossref_local-0.3.0 → crossref_local-0.3.1}/src/crossref_local/aio.py +0 -0
  84. {crossref_local-0.3.0 → crossref_local-0.3.1}/src/crossref_local/citations.py +0 -0
  85. {crossref_local-0.3.0 → crossref_local-0.3.1}/src/crossref_local/impact_factor/__init__.py +0 -0
  86. {crossref_local-0.3.0 → crossref_local-0.3.1}/src/crossref_local/impact_factor/calculator.py +0 -0
  87. {crossref_local-0.3.0 → crossref_local-0.3.1}/src/crossref_local/impact_factor/journal_lookup.py +0 -0
  88. {crossref_local-0.3.0 → crossref_local-0.3.1}/src/crossref_local/models.py +0 -0
  89. {crossref_local-0.3.0 → crossref_local-0.3.1}/tests/conftest.py +0 -0
  90. {crossref_local-0.3.0 → crossref_local-0.3.1}/tests/crossref_local/impact_factor/test_calculator.py +0 -0
  91. {crossref_local-0.3.0 → crossref_local-0.3.1}/tests/crossref_local/impact_factor/test_journal_lookup.py +0 -0
  92. {crossref_local-0.3.0 → crossref_local-0.3.1}/tests/crossref_local/test_api.py +0 -0
  93. {crossref_local-0.3.0 → crossref_local-0.3.1}/tests/crossref_local/test_models.py +0 -0
  94. {crossref_local-0.3.0 → crossref_local-0.3.1}/tests/fixtures/.gitkeep +0 -0
  95. {crossref_local-0.3.0 → crossref_local-0.3.1}/tests/sync_tests_with_source.sh +0 -0
  96. {crossref_local-0.3.0 → crossref_local-0.3.1}/vendor/dois2sqlite/.gitignore +0 -0
  97. {crossref_local-0.3.0 → crossref_local-0.3.1}/vendor/dois2sqlite/LICENSE +0 -0
  98. {crossref_local-0.3.0 → crossref_local-0.3.1}/vendor/dois2sqlite/NOTES.md +0 -0
  99. {crossref_local-0.3.0 → crossref_local-0.3.1}/vendor/dois2sqlite/README.md +0 -0
  100. {crossref_local-0.3.0 → crossref_local-0.3.1}/vendor/dois2sqlite/dois2sqlite/__init__.py +0 -0
  101. {crossref_local-0.3.0 → crossref_local-0.3.1}/vendor/dois2sqlite/dois2sqlite/cli.py +0 -0
  102. {crossref_local-0.3.0 → crossref_local-0.3.1}/vendor/dois2sqlite/dois2sqlite/database.py +0 -0
  103. {crossref_local-0.3.0 → crossref_local-0.3.1}/vendor/dois2sqlite/dois2sqlite/file_handlers.py +0 -0
  104. {crossref_local-0.3.0 → crossref_local-0.3.1}/vendor/dois2sqlite/dois2sqlite/models.py +0 -0
  105. {crossref_local-0.3.0 → crossref_local-0.3.1}/vendor/dois2sqlite/dois2sqlite/representations.py +0 -0
  106. {crossref_local-0.3.0 → crossref_local-0.3.1}/vendor/dois2sqlite/dois2sqlite/utils.py +0 -0
  107. {crossref_local-0.3.0 → crossref_local-0.3.1}/vendor/dois2sqlite/examples/cnserver/NOTES.md +0 -0
  108. {crossref_local-0.3.0 → crossref_local-0.3.1}/vendor/dois2sqlite/examples/cnserver/README.md +0 -0
  109. {crossref_local-0.3.0 → crossref_local-0.3.1}/vendor/dois2sqlite/examples/cnserver/app.py +0 -0
  110. {crossref_local-0.3.0 → crossref_local-0.3.1}/vendor/dois2sqlite/examples/cnserver/cn-quick-test.py +0 -0
  111. {crossref_local-0.3.0 → crossref_local-0.3.1}/vendor/dois2sqlite/examples/cnserver/cnserver/__init__.py +0 -0
  112. {crossref_local-0.3.0 → crossref_local-0.3.1}/vendor/dois2sqlite/examples/cnserver/cnserver/accept_header_utils.py +0 -0
  113. {crossref_local-0.3.0 → crossref_local-0.3.1}/vendor/dois2sqlite/examples/cnserver/cnserver/cslutils.py +0 -0
  114. {crossref_local-0.3.0 → crossref_local-0.3.1}/vendor/dois2sqlite/examples/cnserver/cnserver/settings.py +0 -0
  115. {crossref_local-0.3.0 → crossref_local-0.3.1}/vendor/dois2sqlite/pyproject.toml +0 -0
  116. {crossref_local-0.3.0 → crossref_local-0.3.1}/vendor/dois2sqlite/quick_convert.sh +0 -0
  117. {crossref_local-0.3.0 → crossref_local-0.3.1}/vendor/dois2sqlite/quick_no_convert.sh +0 -0
  118. {crossref_local-0.3.0 → crossref_local-0.3.1}/vendor/dois2sqlite/utils/create-rnd-tar-subset.py +0 -0
  119. {crossref_local-0.3.0 → crossref_local-0.3.1}/vendor/dois2sqlite/utils/select-rnd-dois-from-db.py +0 -0
  120. {crossref_local-0.3.0 → crossref_local-0.3.1}/vendor/labs-data-file-api/.gitignore +0 -0
  121. {crossref_local-0.3.0 → crossref_local-0.3.1}/vendor/labs-data-file-api/LICENSE.md +0 -0
  122. {crossref_local-0.3.0 → crossref_local-0.3.1}/vendor/labs-data-file-api/README.md +0 -0
  123. {crossref_local-0.3.0 → crossref_local-0.3.1}/vendor/labs-data-file-api/crossrefDataFile/__init__.py +0 -0
  124. {crossref_local-0.3.0 → crossref_local-0.3.1}/vendor/labs-data-file-api/crossrefDataFile/api.py +0 -0
  125. {crossref_local-0.3.0 → crossref_local-0.3.1}/vendor/labs-data-file-api/crossrefDataFile/app_urls.py +0 -0
  126. {crossref_local-0.3.0 → crossref_local-0.3.1}/vendor/labs-data-file-api/crossrefDataFile/asgi.py +0 -0
  127. {crossref_local-0.3.0 → crossref_local-0.3.1}/vendor/labs-data-file-api/crossrefDataFile/migrations/0001_initial.py +0 -0
  128. {crossref_local-0.3.0 → crossref_local-0.3.1}/vendor/labs-data-file-api/crossrefDataFile/migrations/0002_dataindexwithlocation.py +0 -0
  129. {crossref_local-0.3.0 → crossref_local-0.3.1}/vendor/labs-data-file-api/crossrefDataFile/migrations/__init__.py +0 -0
  130. {crossref_local-0.3.0 → crossref_local-0.3.1}/vendor/labs-data-file-api/crossrefDataFile/models.py +0 -0
  131. {crossref_local-0.3.0 → crossref_local-0.3.1}/vendor/labs-data-file-api/crossrefDataFile/settings.py +0 -0
  132. {crossref_local-0.3.0 → crossref_local-0.3.1}/vendor/labs-data-file-api/crossrefDataFile/urls.py +0 -0
  133. {crossref_local-0.3.0 → crossref_local-0.3.1}/vendor/labs-data-file-api/crossrefDataFile/views.py +0 -0
  134. {crossref_local-0.3.0 → crossref_local-0.3.1}/vendor/labs-data-file-api/crossrefDataFile/wsgi.py +0 -0
  135. {crossref_local-0.3.0 → crossref_local-0.3.1}/vendor/labs-data-file-api/main.py +0 -0
  136. {crossref_local-0.3.0 → crossref_local-0.3.1}/vendor/labs-data-file-api/manage.py +0 -0
@@ -24,7 +24,7 @@ jobs:
24
24
  - name: Install dependencies
25
25
  run: |
26
26
  python -m pip install --upgrade pip
27
- pip install -e ".[dev]"
27
+ pip install -e ".[all]"
28
28
 
29
29
  - name: Create test database
30
30
  run: |
@@ -680,3 +680,4 @@ GITIGNORED/
680
680
  # Test fixtures (generated)
681
681
  tests/fixtures/*.db
682
682
  tests/fixtures/*.json
683
+ _.venv/
@@ -5,6 +5,25 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.3.1] - 2026-01-14
9
+
10
+ ### Added
11
+ - FastAPI HTTP server with RESTful endpoints (`/works`, `/works/{doi}`, `/works/batch`)
12
+ - MCP server for Claude Desktop integration (`crossref-local serve`)
13
+ - Remote client for accessing API over SSH tunnel
14
+ - Comprehensive test suite (114 tests covering all modules)
15
+ - Shell scripts with proper usage/help options
16
+
17
+ ### Changed
18
+ - Renamed API endpoints to RESTful conventions (`/search` → `/works`)
19
+ - Cleaned up Python API exposure - internal modules no longer in `__all__`
20
+ - Improved module docstrings with full API documentation
21
+
22
+ ### Fixed
23
+ - SQLite threading issue for FastAPI multi-threaded access
24
+ - Batch endpoint path in remote client
25
+ - FastMCP API compatibility (`description` → `instructions`)
26
+
8
27
  ## [0.3.0] - 2026-01-11
9
28
 
10
29
  ### Added
@@ -7,7 +7,7 @@
7
7
  # make status - Show database status
8
8
 
9
9
  .PHONY: help install dev test status db-info db-schema db-indices fts-build fts-status \
10
- citations-status citations-rebuild check clean
10
+ citations-status citations-rebuild check clean nfs-setup nfs-status nfs-stop
11
11
 
12
12
  # Paths
13
13
  PROJECT_ROOT := $(shell pwd)
@@ -149,6 +149,9 @@ status: ## Show overall system status (run this first!)
149
149
  echo " Hint: Check data symlink or run 'make download'"; \
150
150
  fi
151
151
  @echo ""
152
+ @echo "=== NFS Server ==="
153
+ @$(SCRIPTS)/nfs/check.sh
154
+ @echo ""
152
155
  @echo "=== Running Processes ==="
153
156
  @ps aux | grep -E "(rebuild_citations|build_fts|sqlite3)" | grep -v grep | head -5 || echo " No database processes running"
154
157
  @echo ""
@@ -162,6 +165,7 @@ status: ## Show overall system status (run this first!)
162
165
  fi
163
166
  @echo ""
164
167
  @echo "For detailed database info: make db-info"
168
+ @echo "For NFS details: make nfs-status"
165
169
 
166
170
  db-info: ## Show database tables, indices, and row counts
167
171
  @$(SCRIPTS)/database/99_db_info.sh
@@ -252,3 +256,14 @@ create-missing-indices: ## Create any missing indices
252
256
 
253
257
  maintain-indices: ## Analyze and optimize indices
254
258
  @$(SCRIPTS)/database/99_maintain_indexes.sh
259
+
260
+ ##@ NFS Server
261
+
262
+ nfs-setup: ## Setup NFS server to share database (requires .env with SUDO_PASSWORD)
263
+ @$(SCRIPTS)/nfs/setup_nfs.sh
264
+
265
+ nfs-status: ## Show NFS server status and exports
266
+ @$(SCRIPTS)/nfs/status.sh
267
+
268
+ nfs-stop: ## Stop NFS server
269
+ @$(SCRIPTS)/nfs/stop.sh
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: crossref-local
3
- Version: 0.3.0
3
+ Version: 0.3.1
4
4
  Summary: Local CrossRef database with 167M+ works and full-text search
5
5
  Project-URL: Homepage, https://github.com/ywatanabe1989/crossref_local
6
6
  Project-URL: Repository, https://github.com/ywatanabe1989/crossref_local
@@ -18,9 +18,25 @@ Classifier: Topic :: Database
18
18
  Classifier: Topic :: Scientific/Engineering
19
19
  Requires-Python: >=3.10
20
20
  Requires-Dist: click>=8.0
21
+ Provides-Extra: all
22
+ Requires-Dist: fastapi>=0.100; extra == 'all'
23
+ Requires-Dist: fastmcp>=0.4; extra == 'all'
24
+ Requires-Dist: matplotlib>=3.7; extra == 'all'
25
+ Requires-Dist: networkx>=3.0; extra == 'all'
26
+ Requires-Dist: pytest-asyncio>=0.21; extra == 'all'
27
+ Requires-Dist: pytest-cov>=4.0; extra == 'all'
28
+ Requires-Dist: pytest>=7.0; extra == 'all'
29
+ Requires-Dist: pyvis>=0.3; extra == 'all'
30
+ Requires-Dist: uvicorn>=0.20; extra == 'all'
31
+ Provides-Extra: api
32
+ Requires-Dist: fastapi>=0.100; extra == 'api'
33
+ Requires-Dist: uvicorn>=0.20; extra == 'api'
21
34
  Provides-Extra: dev
35
+ Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
22
36
  Requires-Dist: pytest-cov>=4.0; extra == 'dev'
23
37
  Requires-Dist: pytest>=7.0; extra == 'dev'
38
+ Provides-Extra: mcp
39
+ Requires-Dist: fastmcp>=0.4; extra == 'mcp'
24
40
  Provides-Extra: viz
25
41
  Requires-Dist: matplotlib>=3.7; extra == 'viz'
26
42
  Requires-Dist: networkx>=3.0; extra == 'viz'
@@ -121,24 +137,93 @@ async def main():
121
137
  crossref-local search "CRISPR genome editing" -n 5
122
138
  crossref-local get 10.1038/nature12373
123
139
  crossref-local impact-factor Nature -y 2023 # IF: 54.067
140
+ crossref-local info # Database stats
124
141
  ```
125
142
 
126
143
  With abstracts (`-a` flag):
127
144
  ```
128
- $ crossref-local search "CRISPR" -n 1 -a
145
+ $ crossref-local search "RS-1 enhances CRISPR" -n 1 -a
129
146
 
130
- Found 87,473 matches in 18.2ms
147
+ Found 4 matches in 128.4ms
131
148
 
132
149
  1. RS-1 enhances CRISPR/Cas9- and TALEN-mediated knock-in efficiency (2016)
133
150
  DOI: 10.1038/ncomms10548
134
151
  Journal: Nature Communications
135
152
  Abstract: Zinc-finger nuclease, transcription activator-like effector nuclease
136
- and CRISPR/Cas9 are becoming major tools for genome editing. Importantly,
137
- knock-in in several non-rodent species has been finally achieved...
153
+ and CRISPR/Cas9 are becoming major tools for genome editing...
138
154
  ```
139
155
 
140
156
  </details>
141
157
 
158
+ <details>
159
+ <summary><strong>HTTP API</strong></summary>
160
+
161
+ Start the FastAPI server:
162
+ ```bash
163
+ crossref-local api --host 0.0.0.0 --port 3333
164
+ ```
165
+
166
+ Endpoints:
167
+ ```bash
168
+ # Search works (FTS5)
169
+ curl "http://localhost:3333/works?q=CRISPR&limit=10"
170
+
171
+ # Get by DOI
172
+ curl "http://localhost:3333/works/10.1038/nature12373"
173
+
174
+ # Batch DOI lookup
175
+ curl -X POST "http://localhost:3333/works/batch" \
176
+ -H "Content-Type: application/json" \
177
+ -d '{"dois": ["10.1038/nature12373", "10.1126/science.aax0758"]}'
178
+
179
+ # Database info
180
+ curl "http://localhost:3333/info"
181
+ ```
182
+
183
+ Remote access via SSH tunnel:
184
+ ```bash
185
+ # On local machine
186
+ ssh -L 3333:127.0.0.1:3333 nas
187
+
188
+ # Python client
189
+ from crossref_local import configure_remote
190
+ configure_remote("http://localhost:3333")
191
+ ```
192
+
193
+ </details>
194
+
195
+ <details>
196
+ <summary><strong>MCP Server (Claude Desktop)</strong></summary>
197
+
198
+ Run as MCP server for Claude Desktop integration:
199
+ ```bash
200
+ crossref-local serve
201
+ ```
202
+
203
+ Add to Claude Desktop config (`~/.config/claude/claude_desktop_config.json`):
204
+ ```json
205
+ {
206
+ "mcpServers": {
207
+ "crossref-local": {
208
+ "command": "crossref-local",
209
+ "args": ["serve"],
210
+ "env": {
211
+ "CROSSREF_LOCAL_DB": "/path/to/crossref.db"
212
+ }
213
+ }
214
+ }
215
+ }
216
+ ```
217
+
218
+ Available tools:
219
+ - `search_works` - Full-text search across 167M+ papers
220
+ - `get_work` - Get paper by DOI
221
+ - `count_works` - Count matching papers
222
+ - `database_info` - Database statistics
223
+ - `calculate_impact_factor` - Journal impact factor
224
+
225
+ </details>
226
+
142
227
  <details>
143
228
  <summary><strong>Impact Factor</strong></summary>
144
229
 
@@ -188,6 +273,27 @@ Searching 167M records in milliseconds via FTS5.
188
273
 
189
274
  </details>
190
275
 
276
+ <details>
277
+ <summary><strong>Related Projects</strong></summary>
278
+
279
+ **[openalex-local](https://github.com/ywatanabe1989/openalex-local)** - Sister project with OpenAlex data:
280
+
281
+ | Feature | crossref-local | openalex-local |
282
+ |---------|----------------|----------------|
283
+ | Works | 167M | 284M |
284
+ | Abstracts | ~21% | ~45-60% |
285
+ | Update frequency | Real-time | Monthly |
286
+ | DOI authority | ✓ (source) | Uses CrossRef |
287
+ | Citations | Raw references | Linked works |
288
+ | Concepts/Topics | ❌ | ✓ |
289
+ | Author IDs | ❌ | ✓ |
290
+ | Best for | DOI lookup, raw refs | Semantic search |
291
+
292
+ **When to use CrossRef**: Real-time DOI updates, raw reference parsing, authoritative metadata.
293
+ **When to use OpenAlex**: Semantic search, citation analysis, topic discovery.
294
+
295
+ </details>
296
+
191
297
 
192
298
  ---
193
299
 
@@ -92,24 +92,93 @@ async def main():
92
92
  crossref-local search "CRISPR genome editing" -n 5
93
93
  crossref-local get 10.1038/nature12373
94
94
  crossref-local impact-factor Nature -y 2023 # IF: 54.067
95
+ crossref-local info # Database stats
95
96
  ```
96
97
 
97
98
  With abstracts (`-a` flag):
98
99
  ```
99
- $ crossref-local search "CRISPR" -n 1 -a
100
+ $ crossref-local search "RS-1 enhances CRISPR" -n 1 -a
100
101
 
101
- Found 87,473 matches in 18.2ms
102
+ Found 4 matches in 128.4ms
102
103
 
103
104
  1. RS-1 enhances CRISPR/Cas9- and TALEN-mediated knock-in efficiency (2016)
104
105
  DOI: 10.1038/ncomms10548
105
106
  Journal: Nature Communications
106
107
  Abstract: Zinc-finger nuclease, transcription activator-like effector nuclease
107
- and CRISPR/Cas9 are becoming major tools for genome editing. Importantly,
108
- knock-in in several non-rodent species has been finally achieved...
108
+ and CRISPR/Cas9 are becoming major tools for genome editing...
109
109
  ```
110
110
 
111
111
  </details>
112
112
 
113
+ <details>
114
+ <summary><strong>HTTP API</strong></summary>
115
+
116
+ Start the FastAPI server:
117
+ ```bash
118
+ crossref-local api --host 0.0.0.0 --port 3333
119
+ ```
120
+
121
+ Endpoints:
122
+ ```bash
123
+ # Search works (FTS5)
124
+ curl "http://localhost:3333/works?q=CRISPR&limit=10"
125
+
126
+ # Get by DOI
127
+ curl "http://localhost:3333/works/10.1038/nature12373"
128
+
129
+ # Batch DOI lookup
130
+ curl -X POST "http://localhost:3333/works/batch" \
131
+ -H "Content-Type: application/json" \
132
+ -d '{"dois": ["10.1038/nature12373", "10.1126/science.aax0758"]}'
133
+
134
+ # Database info
135
+ curl "http://localhost:3333/info"
136
+ ```
137
+
138
+ Remote access via SSH tunnel:
139
+ ```bash
140
+ # On local machine
141
+ ssh -L 3333:127.0.0.1:3333 nas
142
+
143
+ # Python client
144
+ from crossref_local import configure_remote
145
+ configure_remote("http://localhost:3333")
146
+ ```
147
+
148
+ </details>
149
+
150
+ <details>
151
+ <summary><strong>MCP Server (Claude Desktop)</strong></summary>
152
+
153
+ Run as MCP server for Claude Desktop integration:
154
+ ```bash
155
+ crossref-local serve
156
+ ```
157
+
158
+ Add to Claude Desktop config (`~/.config/claude/claude_desktop_config.json`):
159
+ ```json
160
+ {
161
+ "mcpServers": {
162
+ "crossref-local": {
163
+ "command": "crossref-local",
164
+ "args": ["serve"],
165
+ "env": {
166
+ "CROSSREF_LOCAL_DB": "/path/to/crossref.db"
167
+ }
168
+ }
169
+ }
170
+ }
171
+ ```
172
+
173
+ Available tools:
174
+ - `search_works` - Full-text search across 167M+ papers
175
+ - `get_work` - Get paper by DOI
176
+ - `count_works` - Count matching papers
177
+ - `database_info` - Database statistics
178
+ - `calculate_impact_factor` - Journal impact factor
179
+
180
+ </details>
181
+
113
182
  <details>
114
183
  <summary><strong>Impact Factor</strong></summary>
115
184
 
@@ -159,6 +228,27 @@ Searching 167M records in milliseconds via FTS5.
159
228
 
160
229
  </details>
161
230
 
231
+ <details>
232
+ <summary><strong>Related Projects</strong></summary>
233
+
234
+ **[openalex-local](https://github.com/ywatanabe1989/openalex-local)** - Sister project with OpenAlex data:
235
+
236
+ | Feature | crossref-local | openalex-local |
237
+ |---------|----------------|----------------|
238
+ | Works | 167M | 284M |
239
+ | Abstracts | ~21% | ~45-60% |
240
+ | Update frequency | Real-time | Monthly |
241
+ | DOI authority | ✓ (source) | Uses CrossRef |
242
+ | Citations | Raw references | Linked works |
243
+ | Concepts/Topics | ❌ | ✓ |
244
+ | Author IDs | ❌ | ✓ |
245
+ | Best for | DOI lookup, raw refs | Semantic search |
246
+
247
+ **When to use CrossRef**: Real-time DOI updates, raw reference parsing, authoritative metadata.
248
+ **When to use OpenAlex**: Semantic search, citation analysis, topic discovery.
249
+
250
+ </details>
251
+
162
252
 
163
253
  ---
164
254
 
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "crossref-local"
7
- version = "0.3.0"
7
+ version = "0.3.1"
8
8
  description = "Local CrossRef database with 167M+ works and full-text search"
9
9
  readme = "README.md"
10
10
  license = "AGPL-3.0"
@@ -41,15 +41,27 @@ dependencies = [
41
41
  dev = [
42
42
  "pytest>=7.0",
43
43
  "pytest-cov>=4.0",
44
+ "pytest-asyncio>=0.21",
44
45
  ]
45
46
  viz = [
46
47
  "pyvis>=0.3",
47
48
  "networkx>=3.0",
48
49
  "matplotlib>=3.7",
49
50
  ]
51
+ mcp = [
52
+ "fastmcp>=0.4",
53
+ ]
54
+ api = [
55
+ "fastapi>=0.100",
56
+ "uvicorn>=0.20",
57
+ ]
58
+ all = [
59
+ "crossref-local[dev,viz,mcp,api]",
60
+ ]
50
61
 
51
62
  [project.scripts]
52
63
  crossref-local = "crossref_local.cli:main"
64
+ crossref-local-mcp = "crossref_local.mcp_server:main"
53
65
 
54
66
  [project.urls]
55
67
  Homepage = "https://github.com/ywatanabe1989/crossref_local"
@@ -61,3 +73,4 @@ packages = ["src/crossref_local"]
61
73
  [tool.pytest.ini_options]
62
74
  testpaths = ["tests"]
63
75
  python_files = ["test_*.py"]
76
+ asyncio_mode = "auto"
@@ -0,0 +1,132 @@
1
+ # Scripts Directory
2
+
3
+ Helper scripts for CrossRef Local database management and deployment.
4
+
5
+ ## Directory Structure
6
+
7
+ ```
8
+ scripts/
9
+ ├── database/ # Database maintenance scripts
10
+ │ ├── 00_rebuild_all.sh
11
+ │ ├── 02_create_missing_indexes.sh
12
+ │ ├── 99_db_info.sh
13
+ │ ├── 99_maintain_indexes.sh
14
+ │ └── 99_switch_to_optimized.sh
15
+ └── deployment/ # Container deployment
16
+ ├── install_apptainer.sh
17
+ ├── build_apptainer.sh
18
+ ├── run_apptainer.sh
19
+ └── run_docker.sh
20
+ ```
21
+
22
+ ## Database Scripts
23
+
24
+ ### `database/00_rebuild_all.sh`
25
+
26
+ Full database rebuild from Crossref Public Data File.
27
+
28
+ ```bash
29
+ ./scripts/database/00_rebuild_all.sh --help
30
+ ./scripts/database/00_rebuild_all.sh all # Full rebuild (~10-14 days)
31
+ ./scripts/database/00_rebuild_all.sh fts # Rebuild FTS index only
32
+ ```
33
+
34
+ ### `database/02_create_missing_indexes.sh`
35
+
36
+ Create missing indexes on citations table.
37
+
38
+ ```bash
39
+ ./scripts/database/02_create_missing_indexes.sh --help
40
+ ./scripts/database/02_create_missing_indexes.sh # Default database
41
+ ./scripts/database/02_create_missing_indexes.sh --dry-run # Preview changes
42
+ ```
43
+
44
+ ### `database/99_db_info.sh`
45
+
46
+ Display database schema, tables, indices, and row counts.
47
+
48
+ ```bash
49
+ ./scripts/database/99_db_info.sh --help
50
+ ./scripts/database/99_db_info.sh # Quick summary
51
+ ./scripts/database/99_db_info.sh --full # Full schema dump
52
+ ./scripts/database/99_db_info.sh --tables # Tables and counts only
53
+ ```
54
+
55
+ ### `database/99_maintain_indexes.sh`
56
+
57
+ Check and create missing database indexes.
58
+
59
+ ```bash
60
+ ./scripts/database/99_maintain_indexes.sh --help
61
+ ./scripts/database/99_maintain_indexes.sh # Check/create indexes
62
+ ./scripts/database/99_maintain_indexes.sh --check-only # Only check, don't modify
63
+ ```
64
+
65
+ ## Deployment Scripts
66
+
67
+ ### `deployment/install_apptainer.sh`
68
+
69
+ Install Apptainer container runtime.
70
+
71
+ ```bash
72
+ ./scripts/deployment/install_apptainer.sh --help
73
+ ./scripts/deployment/install_apptainer.sh # Install default version
74
+ ./scripts/deployment/install_apptainer.sh -v 1.2.5 # Specific version
75
+ ```
76
+
77
+ ### `deployment/build_apptainer.sh`
78
+
79
+ Build Apptainer/Singularity container image.
80
+
81
+ ```bash
82
+ ./scripts/deployment/build_apptainer.sh --help
83
+ ./scripts/deployment/build_apptainer.sh # Build with defaults
84
+ ./scripts/deployment/build_apptainer.sh --force # Force rebuild
85
+ ```
86
+
87
+ ### `deployment/run_apptainer.sh`
88
+
89
+ Run crossref-local with Apptainer container.
90
+
91
+ ```bash
92
+ ./scripts/deployment/run_apptainer.sh --help
93
+ ./scripts/deployment/run_apptainer.sh # Start API server
94
+ ./scripts/deployment/run_apptainer.sh search CRISPR # Run search
95
+ ./scripts/deployment/run_apptainer.sh shell # Interactive shell
96
+ ```
97
+
98
+ ### `deployment/run_docker.sh`
99
+
100
+ Run crossref-local with Docker container.
101
+
102
+ ```bash
103
+ ./scripts/deployment/run_docker.sh --help
104
+ ./scripts/deployment/run_docker.sh # Start API server
105
+ ./scripts/deployment/run_docker.sh search CRISPR # Run search
106
+ ./scripts/deployment/run_docker.sh shell # Interactive shell
107
+ ```
108
+
109
+ ## Quick Reference
110
+
111
+ **First-time setup:**
112
+ ```bash
113
+ # 1. Check/create indexes (do once, takes hours)
114
+ ./scripts/database/99_maintain_indexes.sh
115
+
116
+ # 2. Check database info
117
+ ./scripts/database/99_db_info.sh
118
+
119
+ # 3. Run tests
120
+ make test
121
+ ```
122
+
123
+ **Long-running operations:**
124
+ ```bash
125
+ # Use screen for operations that take hours/days
126
+ screen -S rebuild
127
+ ./scripts/database/00_rebuild_all.sh fts
128
+ # Ctrl-A D to detach
129
+ screen -r rebuild # Reattach
130
+ ```
131
+
132
+ <!-- EOF -->
@@ -0,0 +1,100 @@
1
+ #!/bin/bash
2
+ # -*- coding: utf-8 -*-
3
+ # File: scripts/database/02_create_missing_indexes.sh
4
+ # Description: Create missing indexes on citations table for impact factor calculations
5
+
6
+ set -euo pipefail
7
+
8
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
9
+ PROJECT_ROOT="$(dirname "$(dirname "$SCRIPT_DIR")")"
10
+ DB="${CROSSREF_LOCAL_DB:-${PROJECT_ROOT}/data/crossref.db}"
11
+ LOG_DIR="${PROJECT_ROOT}/logs"
12
+
13
+ # Colors
14
+ RED='\033[0;31m'
15
+ GREEN='\033[0;32m'
16
+ YELLOW='\033[1;33m'
17
+ NC='\033[0m'
18
+
19
+ usage() {
20
+ cat << EOF
21
+ Usage: $(basename "$0") [OPTIONS]
22
+
23
+ Create missing indexes on citations table for impact factor calculations.
24
+ Run in screen for long-running index creation.
25
+
26
+ OPTIONS:
27
+ -d, --db PATH Database path (default: \$CROSSREF_LOCAL_DB or data/crossref.db)
28
+ -n, --dry-run Show what would be done without executing
29
+ -h, --help Show this help message
30
+
31
+ EXAMPLES:
32
+ $(basename "$0") # Create indexes on default database
33
+ $(basename "$0") --db /path/to.db # Custom database path
34
+
35
+ # Long-running (use screen):
36
+ screen -S index-rebuild
37
+ $(basename "$0")
38
+ # Ctrl-A D to detach
39
+ EOF
40
+ }
41
+
42
+ check_db() {
43
+ if [[ ! -f "$DB" ]]; then
44
+ echo -e "${RED}ERROR: Database not found: ${DB}${NC}" >&2
45
+ exit 1
46
+ fi
47
+ }
48
+
49
+ create_indexes() {
50
+ local LOG="${LOG_DIR}/index_creation_$(date +%Y%m%d_%H%M%S).log"
51
+ mkdir -p "$LOG_DIR"
52
+
53
+ echo "=== Index Creation Started: $(date) ===" | tee -a "$LOG"
54
+ echo "Database: $DB" | tee -a "$LOG"
55
+
56
+ echo "" | tee -a "$LOG"
57
+ echo "Checking existing indexes..." | tee -a "$LOG"
58
+ sqlite3 "$DB" ".indexes citations" | tee -a "$LOG"
59
+
60
+ echo "" | tee -a "$LOG"
61
+ echo "[$(date)] Creating idx_citations_cited_new ON citations(cited_doi, citing_year)..." | tee -a "$LOG"
62
+ time sqlite3 "$DB" "CREATE INDEX IF NOT EXISTS idx_citations_cited_new ON citations(cited_doi, citing_year);" 2>&1 | tee -a "$LOG"
63
+ echo -e "${GREEN}[$(date)] idx_citations_cited_new completed${NC}" | tee -a "$LOG"
64
+
65
+ echo "" | tee -a "$LOG"
66
+ echo "[$(date)] Creating idx_citations_year_new ON citations(citing_year)..." | tee -a "$LOG"
67
+ time sqlite3 "$DB" "CREATE INDEX IF NOT EXISTS idx_citations_year_new ON citations(citing_year);" 2>&1 | tee -a "$LOG"
68
+ echo -e "${GREEN}[$(date)] idx_citations_year_new completed${NC}" | tee -a "$LOG"
69
+
70
+ echo "" | tee -a "$LOG"
71
+ echo "[$(date)] Verifying indexes..." | tee -a "$LOG"
72
+ sqlite3 "$DB" ".indexes citations" | tee -a "$LOG"
73
+
74
+ echo "" | tee -a "$LOG"
75
+ echo "=== Index Creation Completed: $(date) ===" | tee -a "$LOG"
76
+ echo "Log saved to: $LOG"
77
+ }
78
+
79
+ # Parse arguments
80
+ DRY_RUN=0
81
+ while [[ $# -gt 0 ]]; do
82
+ case "$1" in
83
+ -d|--db) DB="$2"; shift 2 ;;
84
+ -n|--dry-run) DRY_RUN=1; shift ;;
85
+ -h|--help) usage; exit 0 ;;
86
+ *) echo -e "${RED}Unknown option: $1${NC}"; usage; exit 1 ;;
87
+ esac
88
+ done
89
+
90
+ check_db
91
+
92
+ if [[ "$DRY_RUN" == "1" ]]; then
93
+ echo -e "${YELLOW}DRY RUN - Would create indexes on: $DB${NC}"
94
+ echo "Indexes to create:"
95
+ echo " - idx_citations_cited_new ON citations(cited_doi, citing_year)"
96
+ echo " - idx_citations_year_new ON citations(citing_year)"
97
+ exit 0
98
+ fi
99
+
100
+ create_indexes