letxinet / backend /tools /metadata.py
C2MV's picture
Initial upload for Build Small Hackathon
68fb5e2 verified
Raw
History Blame Contribute Delete
3.2 kB
import asyncio
from typing import Optional
from backend.providers.base import fetch_json, normalize_result
async def fetch_metadata(doi: str = None, url: str = None, title: str = None) -> dict:
"""Fetch metadata for a single paper."""
if doi:
# Try OpenAlex by DOI
data = await fetch_json(f"https://api.openalex.org/works/https://doi.org/{doi}")
if "error" not in data:
return normalize_result(
title=data.get("title"),
authors=[a.get("author", {}).get("display_name", "") for a in data.get("authorships", [])],
year=data.get("publication_year"),
abstract=None, # Need to decode inverted index
doi=doi,
pdf_url=data.get("open_access", {}).get("oa_url"),
source="openalex",
university=data.get("authorships", [{}])[0].get("institutions", [{}])[0].get("display_name") if data.get("authorships") else None,
citation_count=data.get("cited_by_count"),
)
if title:
data = await fetch_json("https://api.openalex.org/works", params={"search": title, "per-page": 1})
if "error" not in data and data.get("results"):
work = data["results"][0]
return normalize_result(
title=work.get("title"),
authors=[a.get("author", {}).get("display_name", "") for a in work.get("authorships", [])],
year=work.get("publication_year"),
abstract=None,
doi=work.get("ids", {}).get("doi", "").replace("https://doi.org/", ""),
pdf_url=work.get("open_access", {}).get("oa_url"),
source="openalex",
)
return {"error": "No metadata found"}
async def recover_metadata(doi: str = None, url: str = None, title: str = None) -> dict:
"""Deep metadata recovery from multiple sources."""
result = {}
sources_tried = []
# Try OpenAlex
if doi:
sources_tried.append("OpenAlex")
data = await fetch_json(f"https://api.openalex.org/works/https://doi.org/{doi}")
if "error" not in data:
result["title"] = data.get("title")
result["year"] = data.get("publication_year")
result["doi"] = doi
result["authors"] = [a.get("author", {}).get("display_name", "") for a in data.get("authorships", [])]
# Try Crossref for abstract
if doi and not result.get("abstract"):
sources_tried.append("Crossref")
data = await fetch_json(f"https://api.crossref.org/works/{doi}")
if "error" not in data:
item = data.get("message", {})
if item.get("abstract"):
result["abstract"] = item["abstract"][:500]
# Try Semantic Scholar for PDF
if doi and not result.get("pdfUrl"):
sources_tried.append("Semantic Scholar")
data = await fetch_json(f"https://api.semanticscholar.org/graph/v1/paper/DOI:{doi}?fields=openAccessPdf")
if "error" not in data:
result["pdfUrl"] = data.get("openAccessPdf", {}).get("url")
result["sourcesTried"] = sources_tried
return result