Conradf commited on
Commit
53c0860
·
verified ·
1 Parent(s): 86c2108

Upload folder using huggingface_hub

Browse files
Files changed (2) hide show
  1. app/config.py +1 -1
  2. app/fulltext.py +14 -3
app/config.py CHANGED
@@ -26,7 +26,7 @@ class Settings(BaseSettings):
26
  classifier_model_path: str = ""
27
  small_model: str = "gpt-4.1-mini"
28
  narration_model: str = "gpt-4.1"
29
- extraction_limit: int = Field(default=30, ge=0, le=40)
30
  llm_concurrency: int = Field(default=5, ge=1, le=20)
31
  # USD per million tokens: configurable assumptions, never claimed as a bill.
32
  small_input_price: float = 0.4
 
26
  classifier_model_path: str = ""
27
  small_model: str = "gpt-4.1-mini"
28
  narration_model: str = "gpt-4.1"
29
+ extraction_limit: int = Field(default=100, ge=0, le=200)
30
  llm_concurrency: int = Field(default=5, ge=1, le=20)
31
  # USD per million tokens: configurable assumptions, never claimed as a bill.
32
  small_input_price: float = 0.4
app/fulltext.py CHANGED
@@ -9,6 +9,7 @@ its exact-quote validation work unchanged. Papers without a PMCID stay abstract-
9
 
10
  from __future__ import annotations
11
 
 
12
  import logging
13
  import re
14
  import xml.etree.ElementTree as ET
@@ -248,21 +249,31 @@ def flatten_jats(xml_text: str, abstract: str = "", *, max_lines: int = 160) ->
248
  return result
249
 
250
 
 
 
 
251
  class FullTextClient:
252
  """Fetch and flatten one paper's Europe PMC full text; never raises for a missing paper."""
253
 
254
  def __init__(self, config: Settings = settings, transport: httpx.AsyncBaseTransport | None = None):
255
  self.config = config
256
  self.transport = transport
 
 
257
 
258
  def pmcid(self, study: dict) -> str | None:
259
  return normalize_pmcid(study.get("pmcid"))
260
 
261
  async def fetch_xml(self, pmcid: str) -> str | None:
262
  url = f"{self.config.europepmc_url.rstrip('/')}/{pmcid}/fullTextXML"
263
- async with httpx.AsyncClient(
264
- timeout=self.config.fulltext_timeout, transport=self.transport, follow_redirects=True
265
- ) as client:
 
 
 
 
 
266
  response = await client.get(url, headers={"Accept": "application/xml"})
267
  if response.status_code == 404:
268
  return None
 
9
 
10
  from __future__ import annotations
11
 
12
+ import asyncio
13
  import logging
14
  import re
15
  import xml.etree.ElementTree as ET
 
249
  return result
250
 
251
 
252
+ FETCH_CONCURRENCY = 8
253
+
254
+
255
  class FullTextClient:
256
  """Fetch and flatten one paper's Europe PMC full text; never raises for a missing paper."""
257
 
258
  def __init__(self, config: Settings = settings, transport: httpx.AsyncBaseTransport | None = None):
259
  self.config = config
260
  self.transport = transport
261
+ # One search can read a hundred papers; Europe PMC is a shared public service.
262
+ self.slots = asyncio.Semaphore(FETCH_CONCURRENCY)
263
 
264
  def pmcid(self, study: dict) -> str | None:
265
  return normalize_pmcid(study.get("pmcid"))
266
 
267
  async def fetch_xml(self, pmcid: str) -> str | None:
268
  url = f"{self.config.europepmc_url.rstrip('/')}/{pmcid}/fullTextXML"
269
+ async with (
270
+ self.slots,
271
+ httpx.AsyncClient(
272
+ timeout=self.config.fulltext_timeout,
273
+ transport=self.transport,
274
+ follow_redirects=True,
275
+ ) as client,
276
+ ):
277
  response = await client.get(url, headers={"Accept": "application/xml"})
278
  if response.status_code == 404:
279
  return None