API reference¶
Generated from docstrings via mkdocstrings.
narrato.pipeline¶
narrato.pipeline ¶
High-level orchestrator: Compressor chains layers and returns a
CompressionResult. Decoder builds a ready-to-send prompt from the
result.
Compressor
dataclass
¶
End-to-end context compressor.
Parameters¶
source_lang:
ISO code for the source text language. Drives stopword selection.
provider:
"anthropic" or "openai" — used for the extractor LLM call. May
also be a pre-constructed provider instance (useful for testing /
injecting :class:narrato.providers.MockProvider).
extractor_model:
Cheap model used for L3 extraction. e.g. claude-haiku-4-5-20251001
or gpt-4o-mini.
target_model:
Model the downstream prompt will be sent to. Used only for token
accounting in stats.
layers:
Subset of ("preprocess", "codebook", "extract") to run, in order.
schema:
Preset name or Pydantic model class. Only used if extract is in
layers.
preprocess_config / codebook_config:
Override default configs for L1 / L2.
cache:
Enable provider-side prompt caching when supported (Anthropic only as
of v0.2). Reduces cost on repeated calls within the cache TTL.
chunked:
Split very long source text into chunks for the extract layer and
map-reduce the results. Triggers automatically when len(text) >
chunk_chars even if this flag is False — set explicitly to force
chunked mode for testing.
chunk_chars / overlap_chars:
Chunk size and overlap for chunked extraction.
from_profile
classmethod
¶
from_profile(profile: str, *, provider: str | Provider | None = None, extractor_model: str | None = None, target_model: str | None = None, **overrides: Any) -> Compressor
Construct a Compressor from a named profile.
Profile fields become defaults; provider, extractor_model,
target_model and any keyword overrides are applied on top.
Compressor.from_profile("rag-en", provider="openai")
acompress
async
¶
Async equivalent of :meth:compress.
Free layers run synchronously (they are pure CPU and fast); the extract
layer uses the provider's async methods. When chunked mode is active
the chunks are extracted concurrently with the given concurrency.
Requires the configured provider to implement
:class:narrato.providers.AsyncProvider.
CompressionResult
dataclass
¶
payload
instance-attribute
¶
The compressed payload, ready to be embedded in a downstream prompt.
For extract runs this is a JSON object as a string. For runs without
extract this is the rewritten text.
legend
class-attribute
instance-attribute
¶
Codebook legend; empty when codebook layer is not used.
Decoder ¶
Builds the final prompt to send to the downstream LLM.
unpack_prompt
staticmethod
¶
unpack_prompt(result: CompressionResult, instruction: str, *, target_lang: str | None = None) -> str
Return a single-string prompt embedding payload, legend, and instruction.
For Anthropic, this is suitable as the user message. The caller is
free to split the legend onto a cached system prompt instead — see
unpack_messages.
unpack_messages
staticmethod
¶
unpack_messages(result: CompressionResult, instruction: str, *, target_lang: str | None = None) -> dict[str, Any]
Return a {system, user} split so the legend can be cached server-side.
narrato.preprocess¶
narrato.preprocess ¶
Layer 1 — deterministic preprocessing.
No LLM calls. Cheap, language-aware text cleanup that shaves tokens before any downstream stage runs.
Operations (toggleable): - whitespace and punctuation normalization - near-duplicate sentence dedupe (Jaccard over token shingles) - stopword stripping (optional, lang-aware)
Stopword stripping is OFF by default for the narrative preset because narrative
extraction benefits from grammatical context. Turn it on for fact/RAG flows.
PreprocessConfig
dataclass
¶
spacy_model
class-attribute
instance-attribute
¶
When set, use spaCy for sentence splitting and POS-aware token stripping.
May be a full model name (en_core_web_sm) or a short ISO code
(en — maps to the language's default small model). Requires the
nlp extra: pip install 'narratoflow[nlp]' and the model itself
(python -m spacy download <model>). If spaCy is not installed, this
field is silently ignored and the regex-based default is used.
spacy_strip_pos
class-attribute
instance-attribute
¶
When True (and spacy_model is set), drop function-word tokens by POS
instead of dropping stopwords from the bundled word list. Named entities
are preserved.
PreprocessResult
dataclass
¶
narrato.codebook¶
narrato.codebook ¶
Layer 2 — reference compression and codebook substitution.
Builds a per-document codebook of frequent multi-word phrases and assigns each
a short code (e.g. §a, §b). The document is rewritten using the codes,
and the legend is sent alongside so the downstream LLM can decode.
Codes only "win" when the phrase is long enough and frequent enough that the code + one legend entry costs fewer tokens than the original occurrences.
Two savings estimators are supported
"chars"(default, free) — uses character length as a fast proxy."tokens"— measures real token counts via a :class:Tokenizer. More accurate, costs a handful of tokenizer calls per candidate. Pass a tokenizer to :func:buildto enable.
Codes use § followed by base-36 digits. § is rare enough in source text
that collisions are unlikely; we strip it from the input first to be safe.
CodebookConfig
dataclass
¶
estimator
class-attribute
instance-attribute
¶
Either "chars" (default, free) or "tokens" (real-token measurement).
CodebookResult
dataclass
¶
legend_string ¶
Render legend as compact text block for prepending to prompts.
build ¶
build(text: str, cfg: CodebookConfig | None = None, *, tokenizer: _CountableTokenizer | None = None) -> CodebookResult
Build a codebook from text.
Parameters¶
text:
Source text.
cfg:
Codebook configuration (thresholds, max entries, estimator choice).
tokenizer:
Optional tokenizer. When provided and cfg.estimator == "tokens",
savings are computed using real token counts; otherwise char-length is
used as a fast proxy.
decode ¶
Expand codes back to phrases (for testing/debugging round trips).
narrato.extractors¶
narrato.extractors ¶
Layer 3 — semantic extraction via a small/cheap LLM.
The extractor takes the (already preprocessed + codebook'd) text and asks a
cheap model to fill a Pydantic schema. Output is a compact JSON payload — the
densest representation narrato can produce without learned compression.
For sources too long for a single call, use :func:extract_chunked to split
the text, extract each chunk independently, then merge the partial payloads
back into a single schema-conformant object.
Async variants (:func:extract_async, :func:extract_chunked_async) run
chunks concurrently via asyncio.gather and require the provider to
implement :class:narrato.providers.AsyncProvider.
narrato.schemas¶
narrato.schemas ¶
Pydantic schemas that drive the semantic extractor.
A schema describes what to keep from the source text. The extractor LLM is asked to fill it; the filled object is the dense payload sent downstream.
Custom schemas: pass any BaseModel subclass to Compressor(schema=...).
narrato.profiles¶
narrato.profiles ¶
Named compression profiles — opinionated configs on top of the generic core.
A :class:Profile is a frozen bundle of Compressor arguments. Profiles let
users start with one line:
.. code-block:: python
from narrato import Compressor
c = Compressor.from_profile("rag-en")
instead of choosing language, schema, layers, chunk size, etc.
Profiles do not change the engine — they are pure convenience wrappers. The generic core stays language- and domain-neutral; profiles sit on top.
Register your own profiles via :func:register_profile.
narrato.providers¶
narrato.providers.base ¶
Provider abstraction. Concrete impls live in sibling modules.
Provider ¶
Bases: Protocol
AsyncProvider ¶
Bases: Protocol
Structural type for providers exposing async methods.
All built-in providers implement both Provider and AsyncProvider.
Code that wants to require async support can type-hint against this.
ProviderResponse
dataclass
¶
cached_input_tokens
class-attribute
instance-attribute
¶
Tokens that were served from the provider-side prompt cache, when reported.
get_provider ¶
Factory by provider name.
Parameters¶
name:
"anthropic", "openai", or "ollama".
cache:
Enable provider-side prompt caching when supported. Currently honored
by the Anthropic provider (marks the system prompt as an ephemeral
cache breakpoint). Ignored by providers without explicit cache opt-in
(OpenAI's caching is automatic above 1024 tokens; Ollama has none).
narrato.providers.ollama ¶
Ollama provider — local LLMs via the Ollama HTTP API.
Tested against Ollama 0.x. The provider talks to /api/chat and uses
Ollama's format option for structured JSON output. Models that lack tool
or JSON-mode training (e.g. small base models) may produce loose JSON; the
extractor wraps the response and the pipeline reports validation errors
without crashing.
Install Ollama: https://ollama.com — then ollama pull llama3.
This provider has no separate Python SDK requirement: it uses httpx which
is already pulled in as a transitive dependency of anthropic and
openai. Set OLLAMA_HOST (default: http://localhost:11434).
OllamaProvider ¶
narrato.providers.mock ¶
Mock provider for offline tests and demos.
Use with Compressor(provider=MockProvider(payload=...)) after constructing
the compressor — or pass MockProvider instances directly to extract and
run_benchmark.
MockProvider
dataclass
¶
Returns canned responses; counts how many times each method ran.
Parameters¶
payload:
Default JSON payload returned by complete_json. May be a dict or
a callable taking the user prompt and returning a dict.
text:
Default text returned by complete. May be a string or a callable.
sequence:
Optional list of canned ProviderResponse objects returned in order
on successive calls (round-robin if exhausted). Overrides payload
and text when set.
input_tokens / output_tokens:
Token counts reported on each response.
narrato.tokenizers¶
narrato.tokenizers ¶
Tokenizer adapters. Unified count(text) across providers.
Anthropic does not ship a public offline tokenizer for Claude 4.x; we fall back
to the SDK's client.messages.count_tokens when available, otherwise to a
character-heuristic estimate. OpenAI uses tiktoken directly.
AnthropicTokenizer
dataclass
¶
Uses Anthropic SDK count_tokens when available; falls back to estimate.
The fallback uses a conservative chars-per-token ratio for Latin-script languages. For Norwegian text it tends to slightly under-estimate, which is acceptable for ratio comparisons.
OpenAITokenizer
dataclass
¶
Uses tiktoken. Works fully offline.
get_tokenizer ¶
Factory by provider name.
Unknown provider names fall back to the OpenAI tokenizer (BPE via tiktoken) so Ollama / mock / custom providers still get a working token counter.
narrato.language¶
narrato.language ¶
Lightweight language detection utilities.
Used when callers pass source_lang="auto" to the compressor. Detection is
done by the optional langdetect library if installed; otherwise a small
heuristic that scores text against bundled stopword lists is used.
The heuristic is good enough to distinguish the 12 bundled languages on most
inputs longer than ~100 characters. For short or mixed-language input,
install langdetect (pip install 'narratoflow[lang]') for better
accuracy.
detect ¶
Detect the ISO 639-1 language code of text.
Order:
- If
langdetectis installed, use it. - Otherwise score against bundled stopword lists.
- If text is too short / no signal, return
default.
narrato.spacy_pipeline¶
narrato.spacy_pipeline ¶
Optional spaCy integration for higher-quality preprocessing.
This module is imported lazily by :mod:narrato.preprocess. spaCy is not
a hard dependency of narratoflow; install it via the nlp extra:
.. code-block:: bash
pip install "narratoflow[nlp]"
python -m spacy download en_core_web_sm # or your language model
When :class:~narrato.preprocess.PreprocessConfig has spacy_model set and
spaCy is importable, the preprocess layer uses spaCy for sentence splitting
and (optionally) for stripping non-content tokens by POS or by lemma. If
spaCy is not installed, the preprocess layer falls back to the regex-based
default with no error.
Public functions:
- :func:
load_model— cached loader; raises a clear error when missing. - :func:
spacy_sentences— sentence-split using spaCy. - :func:
spacy_strip— drop tokens that match a POS filter, preserving order.
Performance: spaCy is heavier than the regex fallback (~10× slower on small docs). It pays off on longer documents and in languages where naïve regex sentence splitting breaks down (German compound words, Finnish, etc.).
load_model
cached
¶
Load and cache a spaCy Language object.
name_or_lang may be either a full model name (en_core_web_sm) or a
short ISO code (en, no). Raises a :class:RuntimeError with a
helpful message if spaCy or the model is not installed.
spacy_sentences ¶
Sentence-split text using spaCy. Falls through with empty list on empty input.
spacy_strip ¶
spacy_strip(text: str, *, model: str, drop_pos: frozenset[str] | set[str] | None = None, keep_entities: bool = True) -> tuple[str, int]
Strip function-word tokens (by POS) while preserving content.
Returns the rewritten text and the count of dropped tokens. Named entities
are kept verbatim regardless of POS when keep_entities is true.
model_for_lang ¶
Best-effort mapping from ISO code to a default small spaCy model.
narrato.benchmark¶
narrato.benchmark ¶
Round-trip benchmark: measure tokens-in, tokens-out, and downstream quality.
Quality is scored by an LLM judge that compares two narratives generated from (a) the full source vs (b) the compressed payload. A score from 1-10 is returned along with a short rationale.
Cost numbers are estimates using the price table below; update as providers change pricing.
BenchmarkReport
dataclass
¶
run_benchmark ¶
run_benchmark(source_text: str, *, instruction: str, compressor: Compressor, target_model: str | None = None, judge_model: str | None = None, skip_quality: bool = False) -> BenchmarkReport
Run an end-to-end benchmark on one document.
judge ¶
judge(reference_narrative: str, candidate_narrative: str, *, provider: Provider, model: str) -> dict