API Reference¶
scrinium.index
¶
index.py — SQLite FTS5 全文检索索引¶
索引字段:title + abstract + conclusion + tags(均可检索) 其余字段(paper_id, authors, year, journal, doi, paper_type, citation_count, md_path) 存储但不参与检索。
FTS schema 版本由 PRAGMA user_version 记录(当前为 _SCHEMA_VERSION);
检测到旧版本时自动 drop 重建 FTS 表并触发全量重索引。
用法: from scrinium.index import build_index, search build_index(papers_dir, db_path) results = search("turbulent boundary layer", db_path)
build_index(papers_dir, db_path, rebuild=False)
¶
建立或增量更新 SQLite FTS5 全文检索索引。
索引字段: title + abstract + conclusion + tags,
均参与全文检索。其余字段(paper_id, authors 等)仅存储。
标签同时同步到 paper_tags 过滤表供 --tag 精确过滤。
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
papers_dir
|
Path
|
已入库论文目录,扫描其中的 |
required |
db_path
|
Path
|
SQLite 数据库路径,不存在时自动创建。 |
required |
rebuild
|
bool
|
为 |
False
|
Returns:
| Type | Description |
|---|---|
int
|
本次索引的论文数量。 |
build_proceedings_index(proceedings_root, db_path, rebuild=False)
¶
Build a keyword index for proceedings child papers.
search(query, db_path, top_k=None, cfg=None, *, year=None, journal=None, paper_type=None, paper_ids=None, tags=None)
¶
FTS5 关键词全文检索。
在 title、abstract、conclusion、tags 字段上执行 FTS5
MATCH,按 BM25 相关性排序返回结果。BM25 按列加权(见
_BM25_WEIGHTS):标题与策展标签命中的权重显著高于正文字段。
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
query
|
str
|
检索词(多词用空格分隔,FTS5 语法)。 |
required |
db_path
|
Path
|
SQLite 索引数据库路径。 |
required |
top_k
|
int | None
|
最多返回条数,为 |
None
|
cfg
|
Config | None
|
可选的 :class: |
None
|
year
|
str | None
|
年份过滤( |
None
|
journal
|
str | None
|
期刊名过滤(LIKE 模糊匹配)。 |
None
|
paper_type
|
str | None
|
论文类型过滤(如 |
None
|
paper_ids
|
set[str] | None
|
论文 UUID 白名单,仅返回集合内的结果。 |
None
|
tags
|
list[str] | None
|
策展标签(canonical 名)列表,AND 语义精确过滤。 |
None
|
Returns:
| Type | Description |
|---|---|
list[dict]
|
匹配的论文字典列表,每项包含 |
list[dict]
|
|
list[dict]
|
|
Raises:
| Type | Description |
|---|---|
FileNotFoundError
|
索引文件或 FTS5 表不存在。 |
search_author(query, db_path, top_k=None, cfg=None, *, year=None, journal=None, paper_type=None, paper_ids=None)
¶
按作者名搜索论文(LIKE 模糊匹配)。
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
query
|
str
|
作者名(或部分名字),不区分大小写。 |
required |
db_path
|
Path
|
SQLite 索引数据库路径。 |
required |
top_k
|
int | None
|
最多返回条数,为 |
None
|
cfg
|
Config | None
|
可选的 :class: |
None
|
year
|
str | None
|
年份过滤( |
None
|
journal
|
str | None
|
期刊名过滤(LIKE 模糊匹配)。 |
None
|
paper_type
|
str | None
|
论文类型过滤(如 |
None
|
paper_ids
|
set[str] | None
|
论文 UUID 白名单,仅返回集合内的结果。 |
None
|
Returns:
| Type | Description |
|---|---|
list[dict]
|
匹配的论文字典列表。 |
top_cited(db_path, top_k=10, *, year=None, journal=None, paper_type=None, paper_ids=None)
¶
按引用量降序返回论文。
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
db_path
|
Path
|
SQLite 索引数据库路径。 |
required |
top_k
|
int
|
最多返回条数。 |
10
|
year
|
str | None
|
年份过滤( |
None
|
journal
|
str | None
|
期刊名过滤(LIKE 模糊匹配)。 |
None
|
paper_type
|
str | None
|
论文类型过滤(如 |
None
|
paper_ids
|
set[str] | None
|
论文 UUID 白名单,仅返回集合内的结果。 |
None
|
Returns:
| Type | Description |
|---|---|
list[dict]
|
论文字典列表,按 |
Raises:
| Type | Description |
|---|---|
FileNotFoundError
|
索引文件或 FTS5 表不存在。 |
search_proceedings(query, db_path, top_k=20, *, year=None, journal=None, paper_type=None)
¶
Keyword search over proceedings child papers.
lookup_paper(db_path, user_input)
¶
查找论文:支持 UUID、dir_name、DOI、专利公开号。
按以下顺序尝试匹配: UUID → dir_name → DOI → publication_number。 公开号查询会自动归一化为大写。
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
db_path
|
Path
|
SQLite 数据库路径。 |
required |
user_input
|
str
|
UUID、目录名、DOI 或专利公开号。 |
required |
Returns:
| Type | Description |
|---|---|
dict | None
|
|
get_references(paper_id, db_path, *, paper_ids=None)
¶
查询论文的参考文献列表。
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
paper_id
|
str
|
论文 UUID。 |
required |
db_path
|
Path
|
SQLite 数据库路径。 |
required |
paper_ids
|
set[str] | None
|
论文 UUID 白名单(仅过滤库内结果)。 |
None
|
Returns:
| Type | Description |
|---|---|
list[dict]
|
参考文献列表,每项含 |
list[dict]
|
库内论文另含 |
get_citing_papers(paper_id, db_path, *, paper_ids=None)
¶
查询哪些本地论文引用了指定论文(库内反向查找)。
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
paper_id
|
str
|
被引论文的 UUID。 |
required |
db_path
|
Path
|
SQLite 数据库路径。 |
required |
paper_ids
|
set[str] | None
|
论文 UUID 白名单。 |
None
|
Returns:
| Type | Description |
|---|---|
list[dict]
|
引用方论文列表,每项含 |
get_shared_references(paper_id_list, db_path, min_shared=2, *, paper_ids=None)
¶
查询多篇论文的共同参考文献。
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
paper_id_list
|
list[str]
|
论文 UUID 列表。 |
required |
db_path
|
Path
|
SQLite 数据库路径。 |
required |
min_shared
|
int
|
最少被几篇论文共同引用才纳入结果。 |
2
|
paper_ids
|
set[str] | None
|
论文 UUID 白名单(仅过滤库内结果)。 |
None
|
Returns:
| Type | Description |
|---|---|
list[dict]
|
共同引用列表,每项含 |
list[dict]
|
库内论文另含 |
scrinium.loader
¶
loader.py — 分层内容加载 + TOC 提取(纯规则)¶
L1: title / authors / year / journal / doi ← JSON 字段 L2: abstract ← JSON 字段 L3: conclusion ← JSON 字段(由 agent 分析后写入) L4: full markdown ← 读 .md 文件
TOC 提取(enrich_toc)¶
纯规则提取:regex 提取所有 # 标题 + 行号,过滤 running headers、 期刊名、论文标题重复等噪声,并按编号推断层级(level)。 结果写入 JSON["toc"]:[{"line": N, "level": N, "title": "..."}]
load_l1(json_path)
¶
加载 L1 层元数据(标题、作者、年份、期刊、DOI)。
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
json_path
|
Path
|
论文 JSON 元数据文件路径。 |
required |
Returns:
| Type | Description |
|---|---|
dict
|
包含 |
dict
|
|
load_l2(json_path)
¶
加载 L2 层摘要文本。
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
json_path
|
Path
|
论文 JSON 元数据文件路径。 |
required |
Returns:
| Type | Description |
|---|---|
str
|
摘要文本,无摘要时返回 |
load_l3(json_path)
¶
加载 L3 层结论文本。
结论由 agent 阅读全文后写入 l3_conclusion 字段。
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
json_path
|
Path
|
论文 JSON 元数据文件路径。 |
required |
Returns:
| Type | Description |
|---|---|
str | None
|
结论文本,尚未写入时返回 |
load_l4(md_path, *, lang=None)
¶
加载 L4 层全文 Markdown,可选加载翻译版本。
当指定 lang 时,优先加载 paper_{lang}.md(如 paper_zh.md),
不存在则回退到原文 paper.md。
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
md_path
|
Path
|
MinerU 输出的 |
required |
lang
|
str | None
|
目标语言代码(如 |
None
|
Returns:
| Type | Description |
|---|---|
str
|
完整 Markdown 文本。 |
load_notes(paper_dir)
¶
加载论文的 agent 分析笔记。
笔记文件 (notes.md) 由 agent 在分析论文时自动创建和追加,
用于跨会话、跨工作区复用分析结论。
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
paper_dir
|
Path
|
论文目录路径(包含 |
required |
Returns:
| Type | Description |
|---|---|
str | None
|
笔记文本,不存在时返回 |
append_notes(paper_dir, section)
¶
向论文笔记文件追加一条分析记录。
如果 notes.md 不存在则创建。每条记录之间用空行分隔。
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
paper_dir
|
Path
|
论文目录路径。 |
required |
section
|
str
|
要追加的笔记内容(Markdown 格式,建议以 |
required |
enrich_toc(json_path, md_path, *, force=False)
¶
纯规则提取论文目录结构,写入 JSON["toc"]。
从 Markdown 中提取所有 # 标题,用规则过滤 running headers、
期刊名、作者名等噪声,并按编号推断层级。
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
json_path
|
Path
|
论文 JSON 元数据文件路径(结果写回此文件)。 |
required |
md_path
|
Path
|
论文 Markdown 文件路径。 |
required |
force
|
bool
|
为 |
False
|
Returns:
| Type | Description |
|---|---|
bool
|
提取成功返回 |
validate_lang(lang)
¶
Validate, normalize, and return a safe language code.
Normalizes to lowercase and strips whitespace before validation,
so config values like "ZH" or " zh " are accepted.
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
scrinium.export
¶
export.py — 论文导出(BibTeX / RIS / Markdown / DOCX 等格式)¶
将 meta.json 转换为标准引用格式输出。
meta_to_bibtex(meta)
¶
Convert a single meta.json dict to a BibTeX entry string.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
meta
|
dict
|
Paper metadata dictionary. |
required |
Returns:
| Type | Description |
|---|---|
str
|
Formatted BibTeX entry string. |
export_bibtex(papers_dir, *, paper_ids=None, year=None, journal=None, paper_type=None)
¶
Export papers to BibTeX format.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
papers_dir
|
Path
|
Root papers directory. |
required |
paper_ids
|
list[str] | None
|
Specific paper dir names to export. None = all. |
None
|
year
|
str | None
|
Year filter (e.g. "2023", "2020-2024"). |
None
|
journal
|
str | None
|
Journal name filter (case-insensitive substring). |
None
|
paper_type
|
str | None
|
Paper type filter (case-insensitive substring). |
None
|
Returns:
| Type | Description |
|---|---|
str
|
Complete BibTeX string with all matching entries. |
scrinium.audit
¶
audit.py — 已入库论文数据质量审计¶
扫描 data/papers/ 中的所有论文,检查元数据完整性、数据质量 和内容一致性问题。返回结构化的问题报告供用户审阅。
规则化检查(无需 LLM): - 关键字段缺失(doi, abstract, year, authors, journal) - 配对完整性(目录内 meta.json / paper.md 是否齐全) - 文件名规范性(目录名不符合 Author-Year-Title 格式) - DOI 重复检测 - arXiv DOI 与 arxiv_id 配对(缺失时预印本去重会漏) - MD 内容过短(可能转换失败) - JSON title 与 MD 首个 H1 不一致 - 策展标签缺失(untagged,所有 paper_type 均提示)
Issue
dataclass
¶
单个审计问题。
Attributes:
| Name | Type | Description |
|---|---|---|
paper_id |
str
|
论文 ID(目录名)。 |
severity |
str
|
严重程度, |
rule |
str
|
检查规则名称。 |
message |
str
|
问题描述。 |
scrinium.workspace
¶
workspace.py — 工作区论文子集管理¶
每个工作区是 workspace/<name>/ 目录,内含 papers.json 索引文件
指向 data/papers/ 中的论文。工作区内可自由存放笔记、代码、草稿等。
create(ws_dir)
¶
创建工作区目录并初始化空 papers.json。
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ws_dir
|
Path
|
工作区目录路径。 |
required |
Returns:
| Type | Description |
|---|---|
Path
|
papers.json 文件路径。 |
add(ws_dir, paper_refs, db_path, *, resolved=None, unresolved=None)
¶
添加论文到工作区。
通过 UUID、目录名或 DOI 解析论文,去重后追加到 papers.json。
当调用方已持有解析好的论文信息时,可通过 resolved 参数直接传入,
跳过逐个 lookup_paper() 查询(避免 O(N) 次 DB 连接开销)。
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ws_dir
|
Path
|
工作区目录路径。 |
required |
paper_refs
|
list[str]
|
论文引用列表(UUID / 目录名 / DOI)。
当 resolved 不为 |
required |
db_path
|
Path
|
index.db 路径,用于 lookup_paper。 |
required |
resolved
|
list[dict] | None
|
预解析的论文列表,每个元素须含 |
None
|
unresolved
|
list[str] | None
|
可选的输出列表;无法解析的引用会被追加进去, 供调用方向用户逐条报告。 |
None
|
Returns:
| Type | Description |
|---|---|
list[dict]
|
新增条目列表。 |
remove(ws_dir, paper_refs, db_path)
¶
从工作区移除论文。
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ws_dir
|
Path
|
工作区目录路径。 |
required |
paper_refs
|
list[str]
|
论文引用列表(UUID / 目录名 / DOI)。 |
required |
db_path
|
Path
|
index.db 路径。 |
required |
Returns:
| Type | Description |
|---|---|
list[dict]
|
被移除的条目列表。 |
list_workspaces(ws_root)
¶
列出所有含 papers.json 的工作区。
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ws_root
|
Path
|
workspace/ 根目录。 |
required |
Returns:
| Type | Description |
|---|---|
list[str]
|
工作区名称列表(排序)。 |
read_paper_ids(ws_dir)
¶
返回工作区中所有论文的 UUID 集合。
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ws_dir
|
Path
|
工作区目录路径。 |
required |
Returns:
| Type | Description |
|---|---|
set[str]
|
UUID 字符串集合,用于搜索过滤。 |
scrinium.papers
¶
papers.py — 论文目录结构的唯一真相源¶
所有模块通过此模块访问论文路径,不自行拼路径。
目录结构:
data/papers/
paper_dir(papers_dir, dir_name)
¶
Return the directory path for a paper.
meta_path(papers_dir, dir_name)
¶
Return the meta.json path for a paper.
md_path(papers_dir, dir_name)
¶
Return the paper.md path for a paper.
iter_paper_dirs(papers_dir)
¶
Yield sorted subdirectories containing meta.json.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
papers_dir
|
Path
|
Root papers directory. |
required |
Yields:
| Type | Description |
|---|---|
Path
|
Path to each paper subdirectory that contains a |
scrinium.proceedings
¶
scrinium.tags
¶
tags.py — Agent 策展标签系统¶
标签是 agent 策展的受控词表(controlled vocabulary),用于补偿纯关键词 检索的词汇鸿沟。标签即主题:不做第二个主题系统。
- 受控词表存
<root>/data/tags.yaml(canonical 名 + 别名 + 描述); - 论文标签存各自
meta.json的"tags"字段(canonical 名列表); - 标签随
build_index进入 FTS5(tags列)与paper_tags过滤表。
词表格式::
tags:
force-field:
aliases: [forcefield, FF, 力场]
description: 分子力场相关
added_by: agent
用法::
from scrinium.tags import paper_tags, register_tag, resolve_tag, set_paper_tags
canonical = resolve_tag(cfg, "FF") # -> "force-field"
register_tag(cfg, "enhanced-sampling") # -> True(新增)
set_paper_tags(paper_dir, ["force-field"])
load_taxonomy(cfg)
¶
加载受控词表;文件不存在或为空时返回空词表。
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cfg
|
Config
|
全局配置(词表路径为 |
required |
Returns:
| Type | Description |
|---|---|
dict
|
|
resolve_tag(cfg, name)
¶
将标签名(canonical 或别名)解析为 canonical 名。
大小写不敏感,同时尝试原样小写与连字符规范化两种形式。
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cfg
|
Config
|
全局配置。 |
required |
name
|
str
|
用户输入的标签名。 |
required |
Returns:
| Type | Description |
|---|---|
str | None
|
canonical 名;未知名返回 |
register_tag(cfg, name, *, added_by='agent', description='', aliases=())
¶
注册新标签到受控词表。
canonical 名规范化为小写连字符式。名称命中既有 canonical 或别名时 视为已存在,不重复注册。
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cfg
|
Config
|
全局配置。 |
required |
name
|
str
|
标签名。 |
required |
added_by
|
str
|
注册来源标记(默认 |
'agent'
|
description
|
str
|
标签描述。 |
''
|
aliases
|
tuple[str, ...] | list[str]
|
别名列表。 |
()
|
Returns:
| Type | Description |
|---|---|
bool
|
新增返回 |
Raises:
| Type | Description |
|---|---|
ValueError
|
标签名规范化后为空。 |
paper_tags(paper_dir)
¶
读取论文标签(meta.json["tags"]);无字段时返回 []。
set_paper_tags(paper_dir, tags)
¶
写入论文标签(去重保序),经原子写更新 meta.json。
all_tags_with_counts(cfg)
¶
扫描全库 meta.json,统计每个标签标注了多少篇论文。
Returns:
| Type | Description |
|---|---|
dict[str, int]
|
|
papers_with_tag(cfg, tag)
¶
返回带有指定标签的论文目录与 meta(别名自动归一)。
标签先经 :func:resolve_tag 解析为 canonical 名;词表中不存在时
回退到 :func:normalize_tag(论文可能带有未注册进词表的标签)。
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cfg
|
Config
|
全局配置。 |
required |
tag
|
str
|
标签名(canonical 或别名)。 |
required |
Returns:
| Type | Description |
|---|---|
list[tuple[Path, dict]]
|
|
topic_overview(cfg)
¶
聚合标签主题总览:词表 + 计数 + 占比 + 未打标论文数。
标签即主题——不做第二个主题系统。词表 canonical 名与论文实际使用 的标签取并集。
Returns:
| Type | Description |
|---|---|
dict
|
|
dict
|
每个主题含 |
dict
|
|
scrinium.explore
¶
explore.py — 学术探索¶
从 OpenAlex 批量拉取论文(支持 ISSN / concept / author / institution /
keyword 等多维度 filter),本地 FTS5 关键词检索。拉取结果的主题分组由
agent(subagent)在 harness 侧完成,框架不做嵌入与聚类。数据存储在
data/explore/<name>/,与主库完全隔离。
用法::
from scrinium.explore import explore_search, fetch_explore
fetch_explore("jfm", issn="0022-1120")
fetch_explore("turbulence", concept="C62520636", year_range="2020-2025")
explore_search("jfm", "turbulent boundary layer")
fetch_explore(name, *, issn=None, concept=None, topic=None, author=None, institution=None, keyword=None, source_type=None, year_range=None, min_citations=None, oa_type=None, sort=None, incremental=False, limit=None, cfg=None)
¶
从 OpenAlex 批量拉取论文(支持多维度 filter)。
使用 cursor-based 分页遍历符合条件的所有论文, 提取 title、abstract、authors 等字段,写入 JSONL 文件。
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
探索库名称(如 |
required |
issn
|
str | None
|
期刊 ISSN 过滤(如 |
None
|
concept
|
str | None
|
OpenAlex concept ID(如 |
None
|
topic
|
str | None
|
OpenAlex topic ID。 |
None
|
author
|
str | None
|
OpenAlex author ID。 |
None
|
institution
|
str | None
|
OpenAlex institution ID。 |
None
|
keyword
|
str | None
|
标题/摘要关键词搜索。 |
None
|
source_type
|
str | None
|
来源类型过滤(journal / conference / repository)。 |
None
|
year_range
|
str | None
|
年份过滤(如 |
None
|
min_citations
|
int | None
|
最小引用量过滤。 |
None
|
oa_type
|
str | None
|
OpenAlex work type 过滤(article / review 等)。 |
None
|
sort
|
str | None
|
排序方式( |
None
|
incremental
|
bool
|
为 |
False
|
limit
|
int | None
|
最多拉取的论文数量上限( |
None
|
cfg
|
Config | None
|
可选的全局配置。 |
None
|
Returns:
| Type | Description |
|---|---|
int
|
本次新拉取的论文数量。 |
explore_search(name, query, *, top_k=20, cfg=None)
¶
在探索库中进行 FTS5 关键词搜索。
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
探索库名称。 |
required |
query
|
str
|
查询文本(先经 |
required |
top_k
|
int
|
返回条数。 |
20
|
cfg
|
Config | None
|
可选的全局配置。 |
None
|
Returns:
| Type | Description |
|---|---|
list[dict]
|
论文列表,按 BM25 排名(标题列权重最高,见 |
list_explore_libs(cfg=None)
¶
列出所有探索库名称。
explore_db_path(name, cfg=None)
¶
Return the SQLite DB path for an explore library.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Explore library name. |
required |
cfg
|
Config | None
|
Optional Config instance; resolved from environment if omitted. |
None
|
Returns:
| Type | Description |
|---|---|
Path
|
Path to |
validate_explore_name(name)
¶
Return True if name is a safe, non-traversing library identifier.
Rejects empty strings, absolute paths, and names that contain path
separators or .. components so that callers cannot escape the
data/explore/ directory.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Candidate explore library name supplied by the user. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
|
scrinium.insights
¶
Research behavior analytics helpers used by the insights CLI.
extract_hot_keywords(search_events, *, top_k=10)
¶
Return the most frequent non-stopword tokens from search events.
aggregate_most_read_titles(read_events, papers_dir, *, top_k=10)
¶
Aggregate read counts by resolved paper title.
build_weekly_read_trend(read_events)
¶
Group read events by ISO year-week key.
recent_unique_read_names(read_events, *, limit=5)
¶
Return recent unique paper names preserving newest-first order.
list_workspace_counts(ws_root)
¶
Return workspace names with paper counts.
scrinium.ingest.extractor
¶
extractor.py — 论文元数据提取器¶
Stage-1 元数据提取(从 MinerU markdown 提取 title/authors/year/doi/journal)。 框架内只保留 RegexExtractor(纯正则,零模型调用);规则失败的疑难件 转入 pending 队列,由 agent/subagent 审查接管。
用法¶
from scrinium.ingest.extractor import get_extractor
extractor = get_extractor()
meta = extractor.extract(Path("paper.md"))
get_extractor()
¶
返回元数据提取器实例(恒为 :class:RegexExtractor)。
Returns:
| Type | Description |
|---|---|
MetadataExtractor
|
class: |
scrinium.ingest.metadata
¶
metadata — 论文元数据提取、API 查询、JSON 输出与文件重命名¶
从 MinerU 转换的学术论文 markdown 文件中提取元数据(标题、作者、年份、DOI、期刊), 通过 Crossref / Semantic Scholar / OpenAlex 三个 API 查询引用量、摘要、论文类型, 输出同名 JSON 元数据文件,并将 md + json 重命名为 {一作}-{年份}-{完整标题} 格式。
子模块
_models — PaperMetadata dataclass + 常量 + HTTP session _extract — markdown 正则解析(title/authors/doi/year/journal) _api — API 查询(Crossref/S2/OA)+ enrich_metadata _abstract — abstract 提取(regex/DOI fetch/backfill) _writer — JSON 序列化 + 文件重命名 _cli — 独立 CLI 命令
PaperMetadata
dataclass
¶
一篇学术论文的完整元数据。
Attributes:
| Name | Type | Description |
|---|---|---|
id |
str
|
UUID,入库时生成,永不改变。 |
title |
str
|
论文标题。 |
authors |
list[str]
|
作者列表。 |
first_author |
str
|
第一作者全名。 |
first_author_lastname |
str
|
第一作者姓氏(用于生成文件名)。 |
year |
int | None
|
发表年份。 |
doi |
str
|
DOI 标识符(不含 |
journal |
str
|
期刊或会议名称。 |
abstract |
str
|
摘要文本。 |
paper_type |
str
|
论文类型(article, review, conference-paper 等)。 |
citation_count_s2 |
int | None
|
Semantic Scholar 引用数。 |
citation_count_openalex |
int | None
|
OpenAlex 引用数。 |
citation_count_crossref |
int | None
|
Crossref 引用数。 |
s2_paper_id |
str
|
Semantic Scholar 论文 ID。 |
openalex_id |
str
|
OpenAlex 论文 ID。 |
crossref_doi |
str
|
Crossref 返回的 DOI。 |
api_sources |
list[str]
|
成功返回数据的 API 列表。 |
references |
list[str]
|
参考文献 DOI 列表(从 Semantic Scholar 获取)。 |
source_file |
str
|
原始文件名。 |
arxiv_id |
str
|
arXiv 标识符(如 |
extraction_method |
str
|
提取方式( |
enrich_metadata(meta)
¶
通过 API 查询补全和覆盖元数据。
查询策略(多层降级): 1. Tier 1 — DOI 直查(三个 API 并行,无限流) 2. Tier 2 — Crossref + OA 标题搜索(严格匹配 ≥0.85) 3. Tier 3 — Crossref + OA 放宽搜索(匹配 ≥0.65) 4. Tier 4 — S2 标题搜索(最后手段,可能被限流) 5. Tier 5 — 本地数据(无 API 结果可用)
合并优先级: Crossref > Semantic Scholar > OpenAlex > 正则提取。
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
meta
|
PaperMetadata
|
已提取的元数据(至少需要 |
required |
Returns:
| Name | Type | Description |
|---|---|---|
同一个 |
PaperMetadata
|
class: |
extract_abstract_from_md(md_path)
¶
从 MinerU 解析的 markdown 文件中提取 Abstract 段落(纯正则)。
规则提取失败时返回 None;调用方应输出 handoff hint,
由 agent 阅读原文后直接写 meta.json 的 abstract 字段。
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
md_path
|
Path
|
MinerU 输出的 |
required |
Returns:
| Type | Description |
|---|---|
str | None
|
提取到的 abstract 文本,无法提取时返回 |
fetch_abstract_by_doi(doi)
¶
通过 DOI 从出版商落地页抓取 abstract。
先用 requests 访问 https://doi.org/<doi> 并跟随重定向,
从 HTML meta 标签提取 abstract。若遭遇 Cloudflare 403,
回退到 curl_cffi(模拟浏览器 TLS 指纹)重试。
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
doi
|
str
|
论文 DOI,如 |
required |
Returns:
| Type | Description |
|---|---|
str | None
|
提取到的 abstract 文本,失败时返回 |
backfill_abstracts(papers_dir, *, dry_run=False, doi_fetch=False)
¶
批量补全或更新论文 abstract(纯正则 + DOI 抓取)。
扫描 papers_dir 下所有 JSON:
- 默认模式:只处理缺 abstract 的论文,从
.md纯正则提取。 doi_fetch=True:对所有有 DOI 的论文尝试从出版商网页抓取官方 abstract。成功则覆盖现有 abstract(官方源优先);失败则保留原有值, 仅对仍无 abstract 的论文 fallback 到.md提取。
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
papers_dir
|
Path
|
已入库论文目录。 |
required |
dry_run
|
bool
|
为 |
False
|
doi_fetch
|
bool
|
为 |
False
|
Returns:
| Type | Description |
|---|---|
dict
|
统计字典:``{"filled": N, "skipped": N, "failed": N, "updated": N, |
dict
|
"failed_dirs": [...]} |
dict
|
供调用方输出 agent 接管 hint。 |
generate_new_stem(meta)
¶
生成标准化文件名 stem: {LastName}-{year}-{FullTitle}。
去除变音符号、LaTeX 公式、非法字符,适用于文件系统。
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
meta
|
PaperMetadata
|
元数据实例。 |
required |
Returns:
| Type | Description |
|---|---|
str
|
文件系统安全的文件名 stem(不含扩展名)。 |
metadata_to_dict(meta)
¶
将 :class:PaperMetadata 转换为可序列化的字典。
输出字段包括 title, authors, year, doi, journal,
abstract, citation_count, ids, api_sources 等。
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
meta
|
PaperMetadata
|
元数据实例。 |
required |
Returns:
| Type | Description |
|---|---|
dict
|
JSON 可序列化的字典。 |
refetch_metadata(json_path)
¶
对已入库论文重新查询 API,补全引用量等字段。
从 JSON 反构造 :class:PaperMetadata,调用 :func:enrich_metadata
重新查询三个 API,然后将新数据合并回 JSON(保留 toc、
l3_conclusion 等已有富化字段)。
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
json_path
|
Path
|
已入库论文的 JSON 文件路径。 |
required |
Returns:
| Type | Description |
|---|---|
bool
|
|
rename_paper(json_path, *, dry_run=False)
¶
根据 JSON 元数据重命名论文目录。
读取 meta.json 中的 first_author_lastname、year、title,
用 :func:generate_new_stem 生成标准目录名。若新旧目录名一致则跳过。
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
json_path
|
Path
|
论文 |
required |
dry_run
|
bool
|
为 |
False
|
Returns:
| Type | Description |
|---|---|
Path | None
|
重命名后的新 |
write_metadata_json(meta, output_path)
¶
将元数据写入 JSON 文件(原子写入)。
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
meta
|
PaperMetadata
|
元数据实例。 |
required |
output_path
|
Path
|
输出 JSON 文件路径。 |
required |
scrinium.ingest.pipeline
¶
pipeline.py — 可组合步骤流水线¶
步骤(scope): inbox — 每个 PDF 依次执行:mineru → extract → dedup → ingest papers — 每篇已入库论文执行:abstract → toc(纯规则) global — 全局执行一次:index
预设: full = mineru, extract, dedup, ingest, index ingest = mineru, extract, dedup, ingest, index enrich = abstract, toc reindex = index
用法(CLI): scrinium pipeline full scrinium pipeline enrich --force scrinium pipeline --steps abstract,toc scrinium pipeline full --dry-run
StepResult
¶
Bases: Enum
流水线步骤返回值。
InboxCtx
dataclass
¶
Inbox 步骤间传递的单文件上下文。
Attributes:
| Name | Type | Description |
|---|---|---|
pdf_path |
Path | None
|
原始 PDF 路径,md-only 入库时为 |
inbox_dir |
Path
|
inbox 目录路径。 |
papers_dir |
Path
|
已入库论文目录路径。 |
existing_dois |
dict[str, Path]
|
已入库论文的 DOI → JSON 路径映射(用于去重)。 |
cfg |
Config
|
全局配置。 |
opts |
PipelineOptions
|
运行选项(:class: |
pending_dir |
Path | None
|
无 DOI 论文的待审目录。 |
md_path |
Path | None
|
Markdown 文件路径(MinerU 输出或直接放入)。 |
meta |
Any
|
提取后的 :class: |
status |
str
|
当前状态, |
run_pipeline(step_names, cfg, opts)
¶
执行指定步骤序列。
按 scope 分三阶段依次执行
- inbox — 逐个文件: mineru → extract → dedup → ingest
- papers — 逐篇已入库论文: abstract → toc(纯规则)
- global — 全局执行一次: index
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
step_names
|
list[str]
|
步骤名称列表,如 |
required |
cfg
|
Config
|
全局配置。 |
required |
opts
|
PipelineOptions | dict[str, Any]
|
运行选项(:class: |
required |
Raises:
| Type | Description |
|---|---|
PipelineError
|
步骤名未知,或 inbox 中的 PDF 需要 MinerU 但本地与云端均不可用。 |
import_external(records, cfg, *, pdf_paths=None, no_api=False, dry_run=False)
¶
从外部来源(Endnote 等)批量导入论文。
对每条记录运行 dedup + ingest,最后一次性重建 index。
如提供 pdf_paths(与 records 索引对齐),入库时自动复制
PDF 到论文目录。
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
records
|
list
|
PaperMetadata 列表。 |
required |
cfg
|
Config
|
全局配置。 |
required |
pdf_paths
|
list[Path | None] | None
|
与 records 对齐的 PDF 路径列表(可选)。 |
None
|
no_api
|
bool
|
跳过 API 查询。 |
False
|
dry_run
|
bool
|
预览模式。 |
False
|
Returns:
| Type | Description |
|---|---|
dict[str, int]
|
统计字典 |
batch_convert_pdfs(cfg)
¶
批量转换已入库论文的 PDF 为 paper.md。
扫描 data/papers/ 中有 PDF 无 paper.md 的论文,
云端模式使用 convert_pdfs_cloud_batch() 真正批量转换,
本地模式逐篇调用。转换后补全缺失的 abstract(纯正则),
最后一次性重建 index。
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cfg
|
Config
|
全局配置。 |
required |
Returns:
| Type | Description |
|---|---|
dict[str, int]
|
统计字典 |
step_index(papers_dir, cfg, opts)
¶
更新 SQLite FTS5 索引(global 作用域)。
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
papers_dir
|
Path
|
论文目录。 |
required |
cfg
|
Config
|
全局配置。 |
required |
opts
|
PipelineOptions | dict[str, Any]
|
运行选项(旧 dict 自动转换为 :class: |
required |
Returns:
| Type | Description |
|---|---|
StepResult
|
|