Metadata-Version: 2.4
Name: booksmart-core
Version: 0.1.0
Summary: Booksmart's book-ingestion pipeline: parsing, structure, extraction, summaries, embeddings — as durable Stage functions consumers drive with their own Runner.
Author-email: Patryk Dwórznik <patryk@dworznik.com>
License-Expression: MIT
License-File: LICENSE
Requires-Python: >=3.12
Requires-Dist: alembic>=1.18.5
Requires-Dist: anthropic>=0.116.0
Requires-Dist: openai>=2.44.0
Requires-Dist: psycopg[binary]>=3.3.4
Requires-Dist: pydantic-settings>=2.14.2
Requires-Dist: pymupdf4llm>=1.28.0
Requires-Dist: qdrant-client<1.19.0,>=1.18.0
Requires-Dist: sqlalchemy>=2.0
Description-Content-Type: text/markdown

# booksmart-core

Booksmart's book-ingestion pipeline as a typed library: parsing, structure
detection, profile generation, knowledge extraction, summaries, and embeddings —
exposed as durable, synchronous Stage functions that a consumer drives with its
own Runner (see ADR 0002).

Core owns the domain: the ORM models, a single dialect-neutral Alembic history
(SQLite and Postgres), object storage, the provider abstractions (Anthropic /
OpenAI / Gemini, plus deterministic fakes), and the Qdrant vector store. It reads
no environment on import — a consumer constructs `Settings` and owns engine and
session lifecycle.

Consumers:

- [`booksmart`](https://github.com/dworznik/booksmart/tree/main/packages/cli) —
  the local CLI (SQLite, embedded Qdrant).
- `booksmart-api` — an Inngest-backed service (Postgres) that wraps each Stage in
  a durable step.

```python
from booksmart_core.database import create_engine, upgrade_to_head
from booksmart_core.runner import execute_run

upgrade_to_head(url)
run_id = execute_run(session_factory, storage_root, book_id, "full")
```

## Search

`booksmart_core.search.search` is the read side of the embedding pipeline, and
the single seam every consumer's search surface sits on — the CLI's `search`
command and booksmart-api's HTTP endpoint call it with the same arguments,
against embedded and served Qdrant respectively.

```python
from booksmart_core.search import search

hits = search(session, vector_store, embedder, "how do deep modules help?", limit=5)
```

It embeds the query with the collection's locked model (refusing a mismatch, ADR
0001), ANN-searches Qdrant, and resolves each hit back to its detached ORM row.

