Spaces:
Sleeping
Sleeping
Download src/graphtrace/pipeline.py from ARslan-Ahamd/graphtrace-bench: direct link, hf CLI and curl.
- Browser
- Download file 4.62 kB
-
https://huggingface.co/spaces/ARslan-Ahamd/graphtrace-bench/resolve/main/src/graphtrace/pipeline.py
- Command line
-
hf download hf://spaces/ARslan-Ahamd/graphtrace-bench/src/graphtrace/pipeline.py
-
curl -L -o pipeline.py https://huggingface.co/spaces/ARslan-Ahamd/graphtrace-bench/resolve/main/src/graphtrace/pipeline.py
4.62 kB
| """Corpus preparation and graph building (file-based; no database).""" | |
| from __future__ import annotations | |
| import json | |
| from collections import Counter | |
| from pathlib import Path | |
| from .canonical import Canonicalizer | |
| from .chunking import chunk_document | |
| from .config import ProjectConfig, load_yaml, manifest, write_json | |
| from .corpus import metric_hits, select_corpus | |
| from .data.qasper import load_split | |
| from .graph import KG, build_graph, save_graph | |
| from .schemas import Chunk, Document, paper_prefix | |
| def read_jsonl(path: str | Path) -> list[dict]: | |
| p = Path(path) | |
| if not p.exists(): | |
| return [] | |
| return [json.loads(x) for x in p.read_text(encoding="utf-8").splitlines() if x.strip()] | |
| def write_jsonl(path: str | Path, rows) -> None: | |
| p = Path(path) | |
| p.parent.mkdir(parents=True, exist_ok=True) | |
| with p.open("w", encoding="utf-8") as f: | |
| for r in rows: | |
| f.write((r.model_dump_json() if hasattr(r, "model_dump_json") else json.dumps(r, ensure_ascii=False)) + "\n") | |
| def prepare_corpus(cfg: ProjectConfig) -> dict: | |
| docs: dict[str, Document] = {} | |
| for split in cfg.corpus.splits: | |
| d, _ = load_split(cfg.paths.raw, split) | |
| docs.update(d) | |
| sel = select_corpus(docs, cfg.corpus.n_papers, cfg.corpus.min_mentions) | |
| papers = [docs[p] for p in sorted(sel.papers)] | |
| chunks: list[Chunk] = [] | |
| for doc in papers: | |
| chunks.extend(chunk_document(doc, cfg.chunking, id_prefix=paper_prefix(doc.doc_id))) | |
| out = Path(cfg.paths.processed) | |
| write_jsonl(out / "papers.jsonl", papers) | |
| write_jsonl(out / "chunks.jsonl", chunks) | |
| metric_df = Counter(m for d in papers for m, n in metric_hits(d).items() if n >= cfg.corpus.min_mentions) | |
| toks = sorted(c.n_tokens for c in chunks) | |
| stats = { | |
| **sel.stats, | |
| "selection_order": sel.papers, | |
| "chunks": len(chunks), | |
| "chunk_tokens_median": toks[len(toks) // 2] if toks else 0, | |
| "chunk_tokens_p90": toks[int(0.9 * len(toks))] if toks else 0, | |
| "corpus_tokens": sum(toks), | |
| "metric_lexicon_df": dict(metric_df.most_common()), | |
| "paper_datasets": sel.mentions, | |
| } | |
| write_json(out / "corpus_manifest.json", manifest({"corpus_config": cfg.corpus.model_dump(), "chunking": cfg.chunking.model_dump(), "stats": stats})) | |
| return stats | |
| def load_corpus(cfg: ProjectConfig) -> tuple[dict[str, Document], list[Chunk]]: | |
| out = Path(cfg.paths.processed) | |
| papers = {d["doc_id"]: Document(**d) for d in read_jsonl(out / "papers.jsonl")} | |
| chunks = [Chunk(**c) for c in read_jsonl(out / "chunks.jsonl")] | |
| if not papers: | |
| raise FileNotFoundError(f"no processed corpus in {out}; run `graphtrace corpus` first") | |
| return papers, chunks | |
| def build_canonicalizer(cfg: ProjectConfig, papers: dict[str, Document]) -> Canonicalizer: | |
| curated = load_yaml(cfg.extraction.curated_aliases).get("aliases", {}) if Path(cfg.extraction.curated_aliases).exists() else {} | |
| texts = [p for d in papers.values() for s in d.sections for p in s.paragraphs] | |
| return Canonicalizer.build(curated, texts) | |
| def build(cfg: ProjectConfig, score_confidence: bool | None = None) -> dict: | |
| papers, _ = load_corpus(cfg) | |
| records = read_jsonl(Path(cfg.paths.graph) / "extractions.jsonl") | |
| if not records: | |
| raise FileNotFoundError("no extractions found; run `graphtrace extract` first") | |
| canon = build_canonicalizer(cfg, papers) | |
| build_stats: dict = {} | |
| nodes, edges, results = build_graph(records, papers, canon, stats=build_stats) | |
| confidence: dict[str, float] = {} | |
| if score_confidence if score_confidence is not None else cfg.extraction.nli_confidence: | |
| from .support import score_edges | |
| from .verification import NLIVerifier | |
| confidence = score_edges(KG(nodes, edges, results), NLIVerifier(cfg.extraction.nli_model)) | |
| edges = [e.model_copy(update={"confidence": confidence.get(e.edge_id)}) for e in edges] | |
| save_graph(cfg.paths.graph, nodes, edges, results, canon.merges) | |
| kg = KG(nodes, edges, results) | |
| stats = kg.stats() | |
| write_json( | |
| Path(cfg.paths.graph) / "graph_manifest.json", | |
| manifest( | |
| { | |
| "stats": stats, | |
| **build_stats, | |
| "alias_merges": len(canon.merges), | |
| "nli_model": cfg.extraction.nli_model if confidence else None, | |
| "min_edge_confidence_for_questions_and_methods": cfg.bench.min_edge_confidence, | |
| "edges_below_min_confidence": len(kg.edges) - len(kg.filtered(cfg.bench.min_edge_confidence).edges), | |
| } | |
| ), | |
| ) | |
| return stats | |