Skip to main content

pntx

pntx is a Python library that turns user-supplied positive/negative text pools into:

  1. Generation — synthesize new text on either side.
  2. Classification — label arbitrary text as positive or negative.

The meaning of "positive" and "negative" is entirely up to you. It doesn't have to be sentiment — it can be formal/casual, policy-compliant/violating, or any other contrast you define with examples. pntx never interprets the pools; it only uses them as few-shot and scoring material. positive and negative are independent pools, not aligned pairs — they don't need to be the same length or otherwise correspond to each other (e.g. sampling straight from an existing labeled dataset works fine). Fitting just one side is also valid, e.g. to smoke-test generation from a single example.

from pntx import PNTX

model = PNTX(backend="llama", model_path="model.gguf")

model.fit(
    positive=["The movie was fantastic", "Support was quick and helpful"],
    negative=["The movie was boring", "Support was slow and unhelpful"],
)

# Generation
texts = model.generate(
    n=20,
    side="positive",
    temperature=1.0,
    dedup=True,          # filter near-duplicates (of each other and of the fitted pools)
    verify=True,         # self-classify and reject anything that doesn't match `side`
    min_confidence=0.8,  # confidence threshold used by verify
)

# Classification
result = model.classify("The staff were incredibly friendly")
result.label        # "positive" | "negative"
result.confidence   # float in [0.0, 1.0]
result == "positive"  # True

results = model.classify_batch(texts)  # batched, not a naive per-item loop

Installation

pntx uses uv for package management.

uv add pntx              # core (zero dependencies)
uv add "pntx[llama]"     # + llama.cpp in-process backend
uv add "pntx[anthropic]" # + Anthropic API backend
uv add "pntx[embeddings]" # + semantic similarity for selectors

The core package has no runtime dependencies. Each backend/feature lives behind its own extra, and using one without installing it raises a clear ImportError with the install command to run.

Backends

pntx runs models two ways:

  • LlamaCppBackend (pntx[llama]) — runs a GGUF model in-process via llama-cpp-python. This is the primary, most-tuned backend: classification uses token log-probabilities directly (score_choices), and batched classification reuses the shared few-shot prefix's KV cache across every item instead of re-evaluating it per item.
  • AnthropicBackend (pntx[anthropic]) — calls the Anthropic Messages API. Since that API doesn't expose log-probabilities, classification asks the model to name the label and parses it out of the response instead (confidence is then a fixed convention value, not a calibrated probability). Batched classification runs requests concurrently (asyncio + a semaphore), not in a sequential loop.
model = PNTX(backend="llama", model_path="model.gguf")
model = PNTX(backend="anthropic", model="claude-...")

# or pass a backend instance directly, e.g. for dependency injection in tests
from pntx.backends.llama import LlamaCppBackend
model = PNTX(backend=LlamaCppBackend(model_path="model.gguf"))

LlamaCppBackend accepts either a local model_path or a repo_id (optionally narrowed to one file with filename) to pull a GGUF model from the Hugging Face Hub via Llama.from_pretrained. Any other keyword — n_ctx, n_gpu_layers, flash_attn, verbose, ... — is forwarded as-is to llama_cpp.Llama:

model = PNTX(
    backend="llama",
    repo_id="Qwen/Qwen2.5-1.5B-Instruct-GGUF",
    filename="*q4_k_m.gguf",
    n_ctx=4096,
    n_gpu_layers=-1,   # offload all layers to GPU
    flash_attn=True,
)

Selecting exemplars

When there are more fitted texts (on either side) than comfortably fit in a prompt, a Selector decides which ones to use — it's called independently for the positive and negative pools:

  • RandomSelector (default) — a uniform random subset.
  • NearestSelector — picks texts most similar to the text being classified; dynamic, per-query selection.
  • DiversitySelector — greedily picks a maximally diverse subset.

Both NearestSelector and DiversitySelector take a similarity_fn. It defaults to a dependency-free character n-gram similarity (pntx.dedup.similarity); pass pntx.embeddings.cosine_similarity_fn() (requires pntx[embeddings]) for semantic similarity instead:

from pntx import PNTX
from pntx.selection import NearestSelector

model = PNTX(backend="llama", model_path="model.gguf", selector=NearestSelector())

Development

uv sync                          # install dev dependencies
uv run pytest                    # unit tests (integration tests are skipped by default)
uv run ruff check .
uv run mypy src tests

Integration tests that hit a real model or API are opt-in:

PNTX_LLAMA_MODEL_PATH=/path/to/model.gguf uv run pytest tests/integration
ANTHROPIC_API_KEY=... uv run pytest tests/integration/test_anthropic_backend.py

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pntx-0.3.0.tar.gz (15.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pntx-0.3.0-py3-none-any.whl (20.2 kB view details)

Uploaded Python 3

File details

Details for the file pntx-0.3.0.tar.gz.

File metadata

  • Download URL: pntx-0.3.0.tar.gz
  • Upload date:
  • Size: 15.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.20

File hashes

Hashes for pntx-0.3.0.tar.gz
Algorithm Hash digest
SHA256 2855902c8580774168fcb7a15a687b18ced6f5a331d29c90c4199aa765ec836b
MD5 482247dc40bde01b90608f68d222b5e2
BLAKE2b-256 26dea5f5ff76c435f6329b2f1f5d43b3c9e253b2b9d530030db75cdd6d5d9466

See more details on using hashes here.

File details

Details for the file pntx-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: pntx-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 20.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.20

File hashes

Hashes for pntx-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5c88cf37b2eeb28b3bbe0be6d03b3eeefc85b1a6dc8d760956ec1149cf76c630
MD5 c15679d9a39916c2fba181faaa58ed4d
BLAKE2b-256 a3f1e946f6498979e191015aa3b0c2771bdb7e897a0c89686f5add2e2633d325

See more details on using hashes here.

Release history Release notifications | RSS feed

0.15.0

2 files

0.14.0

2 files

0.13.0

2 files

0.12.1

2 files

0.12.0

2 files

0.11.0

2 files

0.10.0

2 files

0.9.1

2 files

0.9.0

2 files

0.8.3

2 files

0.8.2

2 files

0.8.1

2 files

0.8.0

2 files

0.7.0

2 files

0.6.1

2 files

0.6.0

2 files

0.5.1

2 files

0.5.0

2 files

0.4.0

2 files

This release

0.3.0 This release

2 files

0.2.0

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page