VotreNomUtilisateurboscherj commited on
Commit
c40d26e
·
1 Parent(s): 5bfa0f6

feat(hf): add research_core module used by HF Space

Browse files
Files changed (1) hide show
  1. research_core.py +106 -0
research_core.py ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Pour HuggingFace
2
+ # research_core.py
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from pathlib import Path
7
+ from typing import List, Optional, Dict
8
+
9
+ import arxiv
10
+
11
+
12
+ # ---------- utils ----------
13
+ def _safe_id(pid: str) -> str:
14
+ """
15
+ Transforme un ID arXiv en nom de fichier sûr.
16
+ Exemple: 'gr-qc/0612006v1' -> 'gr-qc_0612006v1'
17
+ """
18
+ return (
19
+ pid.replace("/", "_")
20
+ .replace("\\", "_")
21
+ .replace(":", "-")
22
+ .strip()
23
+ )
24
+
25
+
26
+ # ---------- API principale (utilisable sans MCP) ----------
27
+ def search_papers(topic: str, max_results: int = 5, base_dir: str | Path = "papers") -> List[str]:
28
+ """
29
+ Recherche des papiers sur arXiv, stocke leur meta en JSON (et un .txt du résumé),
30
+ et retourne la liste des paper_ids arXiv (non ‘safe’, c.-à-d. l’ID d’origine).
31
+
32
+ Dossiers créés: papers/<topic>/
33
+ Fichiers: <safe_id>.json, <safe_id>.txt
34
+ """
35
+ base = Path(base_dir)
36
+ topic_dir = base / topic
37
+ topic_dir.mkdir(parents=True, exist_ok=True)
38
+
39
+ search = arxiv.Search(
40
+ query=topic,
41
+ max_results=max_results,
42
+ sort_by=arxiv.SortCriterion.Relevance,
43
+ )
44
+
45
+ results: List[str] = []
46
+
47
+ for paper in search.results():
48
+ # Champs utiles
49
+ paper_id = paper.get_short_id() # ex: '2508.12345v1' ou 'gr-qc/0612006v1'
50
+ title = paper.title or ""
51
+ summary = (paper.summary or "").strip()
52
+ authors = [a.name for a in getattr(paper, "authors", [])]
53
+ published = paper.published.isoformat() if getattr(paper, "published", None) else None
54
+ url = paper.entry_id or ""
55
+
56
+ # Ecriture sur disque (safe filename)
57
+ safe_id = _safe_id(paper_id)
58
+ data: Dict[str, object] = {
59
+ "paper_id": paper_id, # on garde l'ID original pour retrouver l’article
60
+ "title": title,
61
+ "summary": summary,
62
+ "authors": authors,
63
+ "published": published,
64
+ "url": url,
65
+ "topic": topic,
66
+ }
67
+
68
+ (topic_dir / f"{safe_id}.json").write_text(
69
+ json.dumps(data, ensure_ascii=False, indent=2),
70
+ encoding="utf-8",
71
+ )
72
+
73
+ # Optionnel: résumé brut pour consultation rapide
74
+ (topic_dir / f"{safe_id}.txt").write_text(summary, encoding="utf-8")
75
+
76
+ results.append(paper_id)
77
+
78
+ return results
79
+
80
+
81
+ def extract_info(paper_id: str, base_dir: str | Path = "papers") -> Optional[Dict]:
82
+ """
83
+ Retrouve l’info JSON d’un paper_id (ID d’origine arXiv), en scannant tous les topics.
84
+ Retourne le dict si trouvé, sinon None.
85
+ """
86
+ base = Path(base_dir)
87
+ if not base.exists():
88
+ return None
89
+
90
+ safe = _safe_id(paper_id)
91
+
92
+ # On cherche dans papers/*/<safe_id>.json
93
+ for json_path in base.glob(f"*/{safe}.json"):
94
+ try:
95
+ data = json.loads(json_path.read_text(encoding="utf-8"))
96
+ except Exception:
97
+ continue
98
+
99
+ # Par sécurité, on vérifie qu'on retombe bien sur le paper_id recherché
100
+ if isinstance(data, dict) and data.get("paper_id") == paper_id:
101
+ return data
102
+
103
+ return None
104
+
105
+
106
+ __all__ = ["search_papers", "extract_info"]