A hierarchical knowledge graph over a corpus of nutrition literature — built for grounded, citable answers.
FoodScholar ingests dietary guides, textbooks, and scientific abstracts, builds a three-layer hierarchical graph over the chunked corpus, and serves a retrieval API on top. Every answer traces back to the source chunks that support it.
- Layer A — Backbone. A curated, multi-facet menu of shelves projected from the FoodOn ontology (foods, health, nutrients, dietary patterns, allergies, sustainability).
- Layer B — Themes. Fine-grained topic communities discovered per shelf by two complementary passes — embedding similarity and entity relatedness — then merged.
- Layer C — Cards. LLM-generated write-ups for each shelf and theme, with every claim cited back to source chunks.
conda create -n foodscholar python=3.11 -y
conda activate foodscholar
pip install -e '.[dev]' # add extras (llm, elastic, neo4j, clustering, viz) as neededSee docs: Installation for the extras matrix and local services.
from foodscholar import FoodScholar
from foodscholar.io.chunk import Chunk
# Zero-config: in-memory stores + mock embedder + mock LLM. No services, no keys.
fs = FoodScholar.in_memory()
fs.upsert_chunks([
Chunk(chunk_id="c1", text="Mediterranean diet reduces cardiovascular risk.",
source_doc_id="d1", source_type="abstract", section_type="abstract"),
])
fs.info()For a real build, drive everything from a YAML config and run the phases:
fs = FoodScholar.from_config("config.yaml")
fs.init(); fs.ingest("data/corpus", nel_dir="data/ner"); fs.embed()
fs.build_layer_a(); fs.attach(); fs.build_layer_b(facet="foods"); fs.build_layer_c()
answer = fs.query("Is olive oil heart-healthy?")notebooks/graph_build.ipynb is a clean, phase-by-phase
walk-through with an offline (memory) and a real (elastic + neo4j) mode.
| Quickstart · Configuration | get going, then configure stores/LLM/layers |
| Architecture · Layers A/B/C | the design and the three layers |
| Corpus input · Annotation | the input format and the NER/linking pipeline |
| Building · Exploring · Visualization · Tuning Layer B | task guides |
| API reference | the public surface, from docstrings |
config.example.yaml documents every config field; BRIEF.md is the
original design brief.
Run in the foodscholar conda env (Python 3.11):
conda activate foodscholar
pytest # unit tests
pytest -m integration # requires docker-compose: ES + Neo4j
ruff check src testsThe
baseenv's older NumPy can be incompatible with newer Pythons — always use thefoodscholarenv.
Method-selection provenance (the Layer A bake-off harness) lives under research/ and
is not shipped; run it with pytest research/.
src/foodscholar/
├── facade.py # the FoodScholar facade (entry point)
├── graph_view.py # fs.graph + Shelf/Theme/Card handles
├── config.py # Pydantic config + YAML loader
├── io/ # data contracts (Chunk, Shelf, Theme, Card, Entity)
├── corpus/ # chunk + NEL loading
├── annotate/ # GLiNER NER + dense HNSW linking + embeddings
├── ontology/ # FoodOn loader + lookup (FoodOnAPI)
├── llm/ # provider-agnostic LLM client + fallback chain
├── layer_a/ # backbone projection + aliasing
├── layer_b/ # per-shelf theme discovery (two passes + merge)
├── layer_c/ # cited write-up cards
├── retrieval/ # query API
├── storage/ # protocols + memory / elastic / neo4j adapters
├── viz/ # renderable graph views (incl. the interactive tree)
├── cli/ # typer entry point
└── evaluation/ # gates + scorers
notebooks/graph_build.ipynb # phase-by-phase build + interactive tree
docs/ # Sphinx docs (published on Read the Docs)
research/ # archived method bake-off (not shipped)