agent_search_gateway.academic.enrichment
Post-deduplication open-access enrichment for paper records.
1"""Post-deduplication open-access enrichment for paper records.""" 2 3from __future__ import annotations 4 5import asyncio 6import logging 7from dataclasses import replace 8 9from ..models import OAResolution, PaperRecord 10from ..observability import log_event 11from ..providers.contracts import OAResolver 12 13_LOGGER = logging.getLogger(__name__) 14 15 16async def enrich_paper_records( 17 records: list[PaperRecord], 18 resolver: OAResolver | None, 19) -> list[PaperRecord]: 20 """Enrich DOI-bearing papers without allowing resolver failures to drop records.""" 21 22 if resolver is None: 23 return list(records) 24 cache: dict[str, OAResolution | None] = {} 25 enriched: list[PaperRecord] = [] 26 for record in records: 27 doi = record.identifiers.doi 28 if not doi: 29 enriched.append(record) 30 continue 31 if doi not in cache: 32 try: 33 cache[doi] = await resolver.resolve(doi) 34 except asyncio.CancelledError: 35 raise 36 except Exception as exc: 37 log_event( 38 _LOGGER, 39 logging.DEBUG, 40 "paper_enrichment_failed", 41 resolver=resolver.name, 42 stage="oa_resolve", 43 error_type=type(exc).__name__, 44 ) 45 cache[doi] = None 46 resolution = cache[doi] 47 enriched.append(_apply_resolution(record, resolution)) 48 return enriched 49 50 51def _apply_resolution(record: PaperRecord, resolution: OAResolution | None) -> PaperRecord: 52 if resolution is None: 53 return record 54 return replace( 55 record, 56 pdf_url=record.pdf_url or resolution.pdf_url, 57 is_open_access=( 58 record.is_open_access 59 if record.is_open_access is not None 60 else resolution.is_open_access 61 ), 62 oa_status=record.oa_status or resolution.oa_status, 63 license=record.license or resolution.license, 64 )
async def
enrich_paper_records( records: list[agent_search_gateway.models.PaperRecord], resolver: agent_search_gateway.providers.contracts.OAResolver | None) -> list[agent_search_gateway.models.PaperRecord]:
17async def enrich_paper_records( 18 records: list[PaperRecord], 19 resolver: OAResolver | None, 20) -> list[PaperRecord]: 21 """Enrich DOI-bearing papers without allowing resolver failures to drop records.""" 22 23 if resolver is None: 24 return list(records) 25 cache: dict[str, OAResolution | None] = {} 26 enriched: list[PaperRecord] = [] 27 for record in records: 28 doi = record.identifiers.doi 29 if not doi: 30 enriched.append(record) 31 continue 32 if doi not in cache: 33 try: 34 cache[doi] = await resolver.resolve(doi) 35 except asyncio.CancelledError: 36 raise 37 except Exception as exc: 38 log_event( 39 _LOGGER, 40 logging.DEBUG, 41 "paper_enrichment_failed", 42 resolver=resolver.name, 43 stage="oa_resolve", 44 error_type=type(exc).__name__, 45 ) 46 cache[doi] = None 47 resolution = cache[doi] 48 enriched.append(_apply_resolution(record, resolution)) 49 return enriched
Enrich DOI-bearing papers without allowing resolver failures to drop records.