Skip to content

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

已入库论文目录,扫描其中的 *.json

required
db_path Path

SQLite 数据库路径,不存在时自动创建。

required
rebuild bool

True 时清空旧数据后重建。

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 关键词全文检索。

titleabstractconclusiontags 字段上执行 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.search.top_k 读取。

None
cfg Config | None

可选的 :class:~scrinium.config.Config 实例。

None
year str | None

年份过滤("2023" / "2020-2024" / "2020-")。

None
journal str | None

期刊名过滤(LIKE 模糊匹配)。

None
paper_type str | None

论文类型过滤(如 "review""journal-article")。

None
paper_ids set[str] | None

论文 UUID 白名单,仅返回集合内的结果。

None
tags list[str] | None

策展标签(canonical 名)列表,AND 语义精确过滤。

None

Returns:

Type Description
list[dict]

匹配的论文字典列表,每项包含 paper_id, title,

list[dict]

authors, year, journal, doi, paper_type,

list[dict]

citation_count, tags(标签列表)。

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.search.top_k 读取。

None
cfg Config | None

可选的 :class:~scrinium.config.Config 实例。

None
year str | None

年份过滤("2023" / "2020-2024" / "2020-")。

None
journal str | None

期刊名过滤(LIKE 模糊匹配)。

None
paper_type str | None

论文类型过滤(如 "review""journal-article")。

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

年份过滤("2023" / "2020-2024" / "2020-")。

None
journal str | None

期刊名过滤(LIKE 模糊匹配)。

None
paper_type str | None

论文类型过滤(如 "review""journal-article")。

None
paper_ids set[str] | None

论文 UUID 白名单,仅返回集合内的结果。

None

Returns:

Type Description
list[dict]

论文字典列表,按 citation_count 降序排列。

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

papers_registry 行字典,找不到时返回 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]

参考文献列表,每项含 target_doitarget_id

list[dict]

库内论文另含 titledir_nameyearfirst_author

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]

引用方论文列表,每项含 source_iddir_nametitleyear

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]

共同引用列表,每项含 target_doishared_counttarget_id

list[dict]

库内论文另含 titledir_name

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

包含 paper_id, title, authors, year,

dict

journal, doi 的字典。

load_l2(json_path)

加载 L2 层摘要文本。

Parameters:

Name Type Description Default
json_path Path

论文 JSON 元数据文件路径。

required

Returns:

Type Description
str

摘要文本,无摘要时返回 "[No abstract available]"

load_l3(json_path)

加载 L3 层结论文本。

结论由 agent 阅读全文后写入 l3_conclusion 字段。

Parameters:

Name Type Description Default
json_path Path

论文 JSON 元数据文件路径。

required

Returns:

Type Description
str | None

结论文本,尚未写入时返回 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 输出的 .md 文件路径。

required
lang str | None

目标语言代码(如 "zh"),为 None 时加载原文。

None

Returns:

Type Description
str

完整 Markdown 文本。

load_notes(paper_dir)

加载论文的 agent 分析笔记。

笔记文件 (notes.md) 由 agent 在分析论文时自动创建和追加, 用于跨会话、跨工作区复用分析结论。

Parameters:

Name Type Description Default
paper_dir Path

论文目录路径(包含 meta.json 的目录)。

required

Returns:

Type Description
str | None

笔记文本,不存在时返回 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

True 时覆盖已有 TOC。

False

Returns:

Type Description
bool

提取成功返回 True,失败返回 False

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 lang is not a string, or doesn't match the [a-z]{2,5} pattern (ISO 639-1/3) after normalization.

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

严重程度,"error" | "warning" | "info"

rule str

检查规则名称。

message str

问题描述。

audit_papers(papers_dir)

对论文目录执行全量数据质量审计。

Parameters:

Name Type Description Default
papers_dir Path

已入库论文目录(每篇一目录结构)。

required

Returns:

Type Description
list[Issue]

按严重程度排序的问题列表(error 在前)。

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 不为 None 时本参数被忽略。

required
db_path Path

index.db 路径,用于 lookup_paper。

required
resolved list[dict] | None

预解析的论文列表,每个元素须含 "id""dir_name" 键。提供时跳过 lookup_paper 查询。

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// ├── meta.json # 含 "id": "" 字段 └── paper.md

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 meta.json.

scrinium.proceedings

Helpers for proceedings library storage and iteration.

proceedings_db_path(root)

iter_proceedings_dirs(proceedings_root)

iter_proceedings_papers(proceedings_root)

Yield child-paper rows enriched with proceeding metadata.

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

全局配置(词表路径为 <root>/data/tags.yaml)。

required

Returns:

Type Description
dict

{"tags": {canonical: {"aliases": [...], "description": str, ...}}}

resolve_tag(cfg, name)

将标签名(canonical 或别名)解析为 canonical 名。

大小写不敏感,同时尝试原样小写与连字符规范化两种形式。

Parameters:

Name Type Description Default
cfg Config

全局配置。

required
name str

用户输入的标签名。

required

Returns:

Type Description
str | None

canonical 名;未知名返回 None

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")。

'agent'
description str

标签描述。

''
aliases tuple[str, ...] | list[str]

别名列表。

()

Returns:

Type Description
bool

新增返回 True,已存在返回 False

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]

{tag: 论文数} 字典(未排序)。

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]]

[(paper_dir, meta), ...],按目录名排序。

topic_overview(cfg)

聚合标签主题总览:词表 + 计数 + 占比 + 未打标论文数。

标签即主题——不做第二个主题系统。词表 canonical 名与论文实际使用 的标签取并集。

Returns:

Type Description
dict

{"total_papers": int, "untagged_papers": int, "topics": [...]}

dict

每个主题含 tag / description / aliases / count /

dict

share(占全库论文比例),按 count 降序、同名按字典序。

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

探索库名称(如 "jfm"),用作目录名。

required
issn str | None

期刊 ISSN 过滤(如 "0022-1120")。

None
concept str | None

OpenAlex concept ID(如 "C62520636" = Turbulence)。

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

年份过滤(如 "2020-2025")。

None
min_citations int | None

最小引用量过滤。

None
oa_type str | None

OpenAlex work type 过滤(article / review 等)。

None
sort str | None

排序方式(year_asc / year_desc / relevance / citations 或原始 OpenAlex 表达式)。None 时自动选择: 关键词检索按相关度,纯 filter 拉取按年份升序。

None
incremental bool

True 时追加到现有 JSONL,基于 DOI 去重。

False
limit int | None

最多拉取的论文数量上限(None 表示无限制)。

None
cfg Config | None

可选的全局配置。

None

Returns:

Type Description
int

本次新拉取的论文数量。

在探索库中进行 FTS5 关键词搜索。

Parameters:

Name Type Description Default
name str

探索库名称。

required
query str

查询文本(先经 sanitize_fts_query 净化,与主库策略一致)。

required
top_k int

返回条数。

20
cfg Config | None

可选的全局配置。

None

Returns:

Type Description
list[dict]

论文列表,按 BM25 排名(标题列权重最高,见 _FTS_BM25_WEIGHTS)。

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 explore.db inside the library directory.

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

True when the name is safe to use in path construction.

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:RegexExtractor 实例。

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 标识符(不含 https://doi.org/ 前缀)。

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 标识符(如 2401.12345hep-th/9901001,不含版本后缀)。

extraction_method str

提取方式(doi_lookup | arxiv_lookup | title_search | title_search_relaxed | title_search_s2 | local_only)。

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

已提取的元数据(至少需要 titledoi)。

required

Returns:

Name Type Description
同一个 PaperMetadata

class:PaperMetadata 实例,字段已被 API 数据覆盖/补全。

extract_abstract_from_md(md_path)

从 MinerU 解析的 markdown 文件中提取 Abstract 段落(纯正则)。

规则提取失败时返回 None;调用方应输出 handoff hint, 由 agent 阅读原文后直接写 meta.jsonabstract 字段。

Parameters:

Name Type Description Default
md_path Path

MinerU 输出的 .md 文件路径。

required

Returns:

Type Description
str | None

提取到的 abstract 文本,无法提取时返回 None

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,如 "10.1017/jfm.2024.1191"

required

Returns:

Type Description
str | None

提取到的 abstract 文本,失败时返回 None

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

True 时只预览,不写文件。

False
doi_fetch bool

True 时启用 DOI 网页抓取(官方源优先)。

False

Returns:

Type Description
dict

统计字典:``{"filled": N, "skipped": N, "failed": N, "updated": N,

dict

"failed_dirs": [...]}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(保留 tocl3_conclusion 等已有富化字段)。

Parameters:

Name Type Description Default
json_path Path

已入库论文的 JSON 文件路径。

required

Returns:

Type Description
bool

True 表示有字段被更新,False 表示无变化或查询失败。

rename_paper(json_path, *, dry_run=False)

根据 JSON 元数据重命名论文目录。

读取 meta.json 中的 first_author_lastnameyeartitle, 用 :func:generate_new_stem 生成标准目录名。若新旧目录名一致则跳过。

Parameters:

Name Type Description Default
json_path Path

论文 meta.json 文件路径。

required
dry_run bool

True 时只返回新路径,不实际重命名。

False

Returns:

Type Description
Path | None

重命名后的新 meta.json 路径,未变更时返回 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 入库时为 None

inbox_dir Path

inbox 目录路径。

papers_dir Path

已入库论文目录路径。

existing_dois dict[str, Path]

已入库论文的 DOI → JSON 路径映射(用于去重)。

cfg Config

全局配置。

opts PipelineOptions

运行选项(:class:PipelineOptions;传入旧 dict 会在 __post_init__ 中自动转换)。

pending_dir Path | None

无 DOI 论文的待审目录。

md_path Path | None

Markdown 文件路径(MinerU 输出或直接放入)。

meta Any

提取后的 :class:~scrinium.ingest.metadata.PaperMetadata

status str

当前状态,"pending" | "ingested" | "duplicate" | "needs_review" | "failed" | "skipped"

run_pipeline(step_names, cfg, opts)

执行指定步骤序列。

按 scope 分三阶段依次执行
  1. inbox — 逐个文件: mineru → extract → dedup → ingest
  2. papers — 逐篇已入库论文: abstract → toc(纯规则)
  3. global — 全局执行一次: index

Parameters:

Name Type Description Default
step_names list[str]

步骤名称列表,如 ["extract", "dedup", "ingest"]。 可用步骤见 :data:STEPS

required
cfg Config

全局配置。

required
opts PipelineOptions | dict[str, Any]

运行选项(:class:PipelineOptions;旧 dict 自动转换)。 字段说明见 :class:PipelineOptionsinbox_dir / papers_dirNone 时分别回退到 cfg._root / "data/inbox"cfg.papers_dir

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]

统计字典 {"ingested": N, "duplicate": N, "needs_review": N, "failed": N, "skipped": N}

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]

统计字典 {"converted": N, "failed": N, "skipped": N}

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:PipelineOptions)。

required

Returns:

Type Description
StepResult

StepResult.OK