Clarify available source types in explorer and CLI

This commit is contained in:
welsberr 2026-04-07 06:13:05 -04:00
parent 663fb1973a
commit b26f662af9
6 changed files with 77 additions and 5 deletions

View File

@ -297,7 +297,7 @@ Expand from one or more seed entries:
.venv/bin/python -m citegeist --db library.sqlite3 expand langton1989artificial1 .venv/bin/python -m citegeist --db library.sqlite3 expand langton1989artificial1
``` ```
Choose the source: Choose the graph expansion source:
```bash ```bash
.venv/bin/python -m citegeist --db library.sqlite3 expand langton1989artificial1 --source openalex .venv/bin/python -m citegeist --db library.sqlite3 expand langton1989artificial1 --source openalex
@ -333,12 +333,14 @@ Override the topic phrase:
.venv/bin/python -m citegeist --db library.sqlite3 expand-topic artificial-life --topic-phrase "artificial life alife artificial organisms" .venv/bin/python -m citegeist --db library.sqlite3 expand-topic artificial-life --topic-phrase "artificial life alife artificial organisms"
``` ```
Choose source and relation: Choose graph expansion source and relation:
```bash ```bash
.venv/bin/python -m citegeist --db library.sqlite3 expand-topic artificial-life --source openalex --relation cited_by .venv/bin/python -m citegeist --db library.sqlite3 expand-topic artificial-life --source openalex --relation cited_by
``` ```
Note: graph expansion currently supports `openalex` and `crossref`. Metadata resolution, verification, and bootstrap topic seeding also use `datacite` and `pubmed`.
Control seed and discovery limits: Control seed and discovery limits:
```bash ```bash

View File

@ -45,6 +45,11 @@ The adapter exposes JSON-serializable methods suitable for a local web bridge:
- `verify_bibtex(bibtex_text, context="", limit=5)` - `verify_bibtex(bibtex_text, context="", limit=5)`
- `graph(seed_keys, relation_types=None, depth=1, review_status=None, missing_only=False)` - `graph(seed_keys, relation_types=None, depth=1, review_status=None, missing_only=False)`
The `capabilities()` payload also distinguishes between broader metadata/search sources and narrower graph-expansion sources:
- metadata and topic seeding currently use `crossref`, `datacite`, `openalex`, and `pubmed`
- topic graph expansion currently uses `crossref` and `openalex`
## Browser Contract ## Browser Contract
A demo app can expose a browser object like: A demo app can expose a browser object like:

View File

@ -561,7 +561,7 @@
</label> </label>
<div class="row-3"> <div class="row-3">
<label> <label>
Source Expansion Source
<select id="expand-source"> <select id="expand-source">
<option value="openalex">openalex</option> <option value="openalex">openalex</option>
<option value="crossref">crossref</option> <option value="crossref">crossref</option>
@ -611,6 +611,7 @@
<div id="expand-summary" class="summary-box"> <div id="expand-summary" class="summary-box">
<strong>Expansion Policy</strong> <strong>Expansion Policy</strong>
<p>Use <code>cites</code> to bias toward newer work, or <code>both</code> for broader graph growth. Recursive rounds stop once the recent-entry target is met.</p> <p>Use <code>cites</code> to bias toward newer work, or <code>both</code> for broader graph growth. Recursive rounds stop once the recent-entry target is met.</p>
<p id="expand-source-note">Topic graph expansion currently supports openalex and crossref. Metadata search and bootstrap seeding also use datacite and pubmed.</p>
</div> </div>
</section> </section>
@ -827,6 +828,7 @@
expandPreviewButton: document.getElementById("expand-preview-button"), expandPreviewButton: document.getElementById("expand-preview-button"),
expandCommitButton: document.getElementById("expand-commit-button"), expandCommitButton: document.getElementById("expand-commit-button"),
expandSummary: document.getElementById("expand-summary"), expandSummary: document.getElementById("expand-summary"),
expandSourceNote: document.getElementById("expand-source-note"),
searchQuery: document.getElementById("search-query"), searchQuery: document.getElementById("search-query"),
searchTopic: document.getElementById("search-topic"), searchTopic: document.getElementById("search-topic"),
searchButton: document.getElementById("search-button"), searchButton: document.getElementById("search-button"),
@ -1081,6 +1083,43 @@
`; `;
} }
function populateSelectOptions(select, values, preferredValue) {
if (!select || !Array.isArray(values) || !values.length) return;
const previousValue = select.value;
select.innerHTML = "";
values.forEach((value) => {
const option = document.createElement("option");
option.value = value;
option.textContent = value;
select.appendChild(option);
});
if (values.includes(previousValue)) {
select.value = previousValue;
} else if (values.includes(preferredValue)) {
select.value = preferredValue;
} else {
select.value = values[0];
}
}
function applyCapabilities(capabilities) {
const topicExpansionSources = capabilities?.topic_expansion_sources || capabilities?.graph_expansion_sources || [];
const relationTypes = capabilities?.graph_relation_types || [];
const metadataSources = capabilities?.metadata_sources || [];
if (topicExpansionSources.length) {
populateSelectOptions(els.expandSource, topicExpansionSources, "openalex");
}
if (relationTypes.length) {
populateSelectOptions(els.expandRelation, relationTypes, "cites");
}
if (els.expandSourceNote) {
const expansionText = topicExpansionSources.length ? topicExpansionSources.join(", ") : "openalex, crossref";
const metadataText = metadataSources.length ? metadataSources.join(", ") : "crossref, datacite, openalex, pubmed";
els.expandSourceNote.textContent =
`Topic graph expansion currently supports ${expansionText}. Metadata search and bootstrap seeding also use ${metadataText}.`;
}
}
async function connect() { async function connect() {
setBusy(els.connectButton, true); setBusy(els.connectButton, true);
try { try {
@ -1092,6 +1131,7 @@
const client = createLiteratureExplorerClient(bridge); const client = createLiteratureExplorerClient(bridge);
const capabilities = await client.capabilities(); const capabilities = await client.capabilities();
state.client = client; state.client = client;
applyCapabilities(capabilities);
setStatus(`Connected to ${state.bridgeUrl}`, "ok"); setStatus(`Connected to ${state.bridgeUrl}`, "ok");
setLastOp("connect"); setLastOp("connect");
logActivity("capabilities", capabilities); logActivity("capabilities", capabilities);

View File

@ -9,6 +9,10 @@ from .extract import extract_references
from .storage import BibliographyStore from .storage import BibliographyStore
from .verify import BibliographyVerifier from .verify import BibliographyVerifier
METADATA_SOURCES = ["crossref", "datacite", "openalex", "pubmed"]
GRAPH_EXPANSION_SOURCES = ["crossref", "openalex"]
GRAPH_RELATION_TYPES = ["cites", "cited_by", "both"]
class LiteratureExplorerApi: class LiteratureExplorerApi:
"""JSON-serializable adapter layer for browser or local UI bridges.""" """JSON-serializable adapter layer for browser or local UI bridges."""
@ -41,6 +45,11 @@ class LiteratureExplorerApi:
"graph", "graph",
], ],
"preview_operations": ["bootstrap", "expand_topic"], "preview_operations": ["bootstrap", "expand_topic"],
"metadata_sources": list(METADATA_SOURCES),
"topic_seed_sources": list(METADATA_SOURCES),
"graph_expansion_sources": list(GRAPH_EXPANSION_SOURCES),
"topic_expansion_sources": list(GRAPH_EXPANSION_SOURCES),
"graph_relation_types": list(GRAPH_RELATION_TYPES),
} }
def search(self, query: str, *, limit: int = 20, topic_slug: str | None = None) -> dict[str, object]: def search(self, query: str, *, limit: int = 20, topic_slug: str | None = None) -> dict[str, object]:

View File

@ -198,7 +198,7 @@ def build_parser() -> argparse.ArgumentParser:
"--source", "--source",
choices=["crossref", "openalex"], choices=["crossref", "openalex"],
default="crossref", default="crossref",
help="External source used for graph expansion", help="Graph expansion source",
) )
expand_parser.add_argument( expand_parser.add_argument(
"--relation", "--relation",
@ -221,7 +221,7 @@ def build_parser() -> argparse.ArgumentParser:
"--source", "--source",
choices=["crossref", "openalex"], choices=["crossref", "openalex"],
default="openalex", default="openalex",
help="External source used for topic expansion", help="Topic graph expansion source",
) )
expand_topic_parser.add_argument( expand_topic_parser.add_argument(
"--relation", "--relation",

View File

@ -107,6 +107,22 @@ def test_literature_explorer_api_search_and_show_entry():
store.close() store.close()
def test_literature_explorer_api_capabilities_distinguish_metadata_and_expansion_sources():
store = BibliographyStore()
try:
api = LiteratureExplorerApi(store)
payload = api.capabilities()
assert payload["metadata_sources"] == ["crossref", "datacite", "openalex", "pubmed"]
assert payload["topic_seed_sources"] == ["crossref", "datacite", "openalex", "pubmed"]
assert payload["graph_expansion_sources"] == ["crossref", "openalex"]
assert payload["topic_expansion_sources"] == ["crossref", "openalex"]
assert payload["graph_relation_types"] == ["cites", "cited_by", "both"]
finally:
store.close()
def test_literature_explorer_api_bootstrap_returns_topic_payload(): def test_literature_explorer_api_bootstrap_returns_topic_payload():
store = BibliographyStore() store = BibliographyStore()
try: try: