Intermediate commit
This commit is contained in:
parent
0e9e49df16
commit
3d4cfeff1a
65 changed files with 5507 additions and 333 deletions
|
|
@ -5,6 +5,7 @@ import logging
|
|||
from typing import Any
|
||||
|
||||
from app.services.domains.arxiv.application import ArxivRateLimitError
|
||||
from app.services.domains.arxiv.guards import arxiv_skip_reason_for_item
|
||||
from app.services.domains.openalex.client import OpenAlexBudgetExhaustedError
|
||||
from app.services.domains.publications.types import PublicationListItem
|
||||
from app.services.domains.unpaywall.application import OaResolutionOutcome, resolve_publication_oa_outcomes
|
||||
|
|
@ -17,6 +18,7 @@ logger = logging.getLogger(__name__)
|
|||
class PipelineOutcome:
|
||||
outcome: OaResolutionOutcome | None
|
||||
scholar_candidates: Any | None # Kept for backward compatibility with calling signatures
|
||||
arxiv_rate_limited: bool = False
|
||||
|
||||
|
||||
async def resolve_publication_pdf_outcome_for_row(
|
||||
|
|
@ -24,6 +26,7 @@ async def resolve_publication_pdf_outcome_for_row(
|
|||
row: PublicationListItem,
|
||||
request_email: str | None,
|
||||
openalex_api_key: str | None = None,
|
||||
allow_arxiv_lookup: bool = True,
|
||||
) -> PipelineOutcome:
|
||||
# 1. OpenAlex OA — raises OpenAlexBudgetExhaustedError if budget is gone
|
||||
openalex_outcome = await _openalex_outcome(row, request_email=request_email, openalex_api_key=openalex_api_key)
|
||||
|
|
@ -31,13 +34,29 @@ async def resolve_publication_pdf_outcome_for_row(
|
|||
return PipelineOutcome(openalex_outcome, None)
|
||||
|
||||
# 2. arXiv
|
||||
arxiv_outcome = await _arxiv_outcome(row, request_email=request_email)
|
||||
arxiv_rate_limited = False
|
||||
try:
|
||||
arxiv_outcome = await _arxiv_outcome(
|
||||
row,
|
||||
request_email=request_email,
|
||||
allow_lookup=allow_arxiv_lookup,
|
||||
)
|
||||
except ArxivRateLimitError:
|
||||
arxiv_rate_limited = True
|
||||
arxiv_outcome = None
|
||||
logger.warning(
|
||||
"publications.pdf_resolution.arxiv_rate_limited",
|
||||
extra={
|
||||
"event": "publications.pdf_resolution.arxiv_rate_limited",
|
||||
"publication_id": int(row.publication_id),
|
||||
},
|
||||
)
|
||||
if arxiv_outcome and arxiv_outcome.pdf_url:
|
||||
return PipelineOutcome(arxiv_outcome, None)
|
||||
return PipelineOutcome(arxiv_outcome, None, arxiv_rate_limited=arxiv_rate_limited)
|
||||
|
||||
# 3. Unpaywall (which falls back to Crossref)
|
||||
oa_outcome = await _oa_outcome(row=row, request_email=request_email)
|
||||
return PipelineOutcome(oa_outcome, None)
|
||||
return PipelineOutcome(oa_outcome, None, arxiv_rate_limited=arxiv_rate_limited)
|
||||
|
||||
|
||||
async def _openalex_outcome(
|
||||
|
|
@ -87,9 +106,23 @@ async def _openalex_outcome(
|
|||
return None
|
||||
|
||||
|
||||
async def _arxiv_outcome(row: PublicationListItem, request_email: str | None) -> OaResolutionOutcome | None:
|
||||
async def _arxiv_outcome(
|
||||
row: PublicationListItem,
|
||||
*,
|
||||
request_email: str | None,
|
||||
allow_lookup: bool = True,
|
||||
) -> OaResolutionOutcome | None:
|
||||
from app.services.domains.arxiv.application import discover_arxiv_id_for_publication
|
||||
|
||||
if not allow_lookup:
|
||||
_log_arxiv_skip(row=row, skip_reason="batch_arxiv_cooldown_active")
|
||||
return None
|
||||
|
||||
skip_reason = arxiv_skip_reason_for_item(item=row)
|
||||
if skip_reason is not None:
|
||||
_log_arxiv_skip(row=row, skip_reason=skip_reason)
|
||||
return None
|
||||
|
||||
try:
|
||||
arxiv_id = await discover_arxiv_id_for_publication(item=row, request_email=request_email)
|
||||
if arxiv_id:
|
||||
|
|
@ -103,7 +136,7 @@ async def _arxiv_outcome(row: PublicationListItem, request_email: str | None) ->
|
|||
used_crossref=False,
|
||||
)
|
||||
except ArxivRateLimitError:
|
||||
raise # propagate so the batch loop can stop
|
||||
raise # propagate so orchestration can switch to non-arXiv fallback
|
||||
except Exception as exc:
|
||||
logger.warning(
|
||||
"publications.pdf_resolution.arxiv_failed",
|
||||
|
|
@ -112,6 +145,17 @@ async def _arxiv_outcome(row: PublicationListItem, request_email: str | None) ->
|
|||
return None
|
||||
|
||||
|
||||
def _log_arxiv_skip(*, row: PublicationListItem, skip_reason: str) -> None:
|
||||
logger.info(
|
||||
"publications.pdf_resolution.arxiv_skipped",
|
||||
extra={
|
||||
"event": "publications.pdf_resolution.arxiv_skipped",
|
||||
"publication_id": int(row.publication_id),
|
||||
"skip_reason": skip_reason,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
async def _oa_outcome(
|
||||
*,
|
||||
row: PublicationListItem,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue