Metadata-Version: 2.4
Name: theclassifier
Version: 0.2.0
Summary: Classify text through an API or locally, and train models from your own examples
Author: TrueState
License-Expression: Apache-2.0
Project-URL: Homepage, https://theclassifier.ai
Project-URL: Documentation, https://theclassifier.ai/docs
Project-URL: Repository, https://github.com/truestate-ai/theclassifier
Project-URL: Issues, https://github.com/truestate-ai/theclassifier/issues
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests<3,>=2.32
Provides-Extra: local
Requires-Dist: torch<3,>=2.6; extra == "local"
Requires-Dist: transformers<6,>=4.56; extra == "local"
Requires-Dist: peft<1,>=0.17; extra == "local"
Requires-Dist: accelerate<2,>=1; extra == "local"
Requires-Dist: huggingface-hub<2,>=0.34; extra == "local"
Requires-Dist: safetensors>=0.5; extra == "local"
Provides-Extra: train
Requires-Dist: theclassifier[local]; extra == "train"
Requires-Dist: pandas<4,>=2; extra == "train"
Requires-Dist: numpy<3,>=1.26; extra == "train"
Provides-Extra: serve
Requires-Dist: theclassifier[local]; extra == "serve"
Requires-Dist: fastapi<1,>=0.115; extra == "serve"
Requires-Dist: uvicorn<1,>=0.30; extra == "serve"
Provides-Extra: dev
Requires-Dist: theclassifier[serve]; extra == "dev"
Requires-Dist: theclassifier[train]; extra == "dev"
Requires-Dist: pytest>=8; extra == "dev"
Requires-Dist: httpx; extra == "dev"
Requires-Dist: build; extra == "dev"
Requires-Dist: twine; extra == "dev"
Dynamic: license-file

# The Classifier

Classify text into categories you choose, using the API or your own computer.
You can also train a model from a table of examples, then save it for later.

## Install

Install the Python client:

```sh
pip install --upgrade theclassifier
```

For local use or training, install the training extra instead:

```sh
pip install --upgrade 'theclassifier[train]'
```

Python 3.10 or later is required. API use only needs Requests; training support
adds the libraries needed to run models and work with pandas and NumPy.

## Classify text

Create an account at [theclassifier.ai](https://theclassifier.ai), then create an
API key in the dashboard. Set the `CLASSIFIER_API_KEY` environment variable to your key.
The service URL defaults to `https://api.theclassifier.ai`; set
`CLASSIFIER_API_PUBLIC_URL` to override it, or pass `base_url=` to the constructor.
No other application environment variables are required.

```python
import os
from theclassifier import Classifier

classifier = Classifier(api_key=os.environ["CLASSIFIER_API_KEY"])
result = classifier.classify(
    "Please close my account.",
    choices=["cancellation", "billing", "none"],
)
print(result["results"][0]["selected"]["choice"])
```

`choices` contains the answers the model is allowed to choose. Add `none` when
some text might not fit the other categories; it is not added automatically.
The result includes the selected answer and scores for all choices. Scores are
relative to the choices, not a guarantee that the answer is correct.

For a more specific question:

```python
result = classifier.classify(
    "Please close my account.",
    question="What does the customer want?",
    choices=[
        {"choice": "cancellation", "criteria": "Requests to close an account."},
        {"choice": "billing", "criteria": "Questions about charges or payments."},
        {"choice": "none", "criteria": "Neither of the other categories fits."},
    ],
)
```

## Choose a model

The defaults are `version="latest"` and `domain="general"`.
`version` selects a model release; `domain` selects its area of use.
Currently `latest`, `1.1` and `1.1.0` refer to model release 1.1.0.
The package version (0.2.0) and model version (1.1.0) are separate.

| Domain | Use it for |
| --- | --- |
| general | General text classification; start here if unsure |
| intent | What a customer wants to do |
| sentiment | Positive, neutral or negative language |
| triage | Support ticket categories |
| cause | The issue or reason reported in a complaint |
| codify | Product and service categories |
| complaints | Financial complaint products and issues |
| stars | One-to-five review ratings |

```python
result = classifier.classify(
    "Great service!",
    choices=["positive", "neutral", "negative"],
    domain="sentiment",
    version="1.1",
)
```

Versions and domains are discovered from [Hugging Face](https://huggingface.co/TrueState/theclassifier):

```python
from theclassifier import available_versions, available_domains

print(available_versions())
print(available_domains(version="latest"))
```

Local `latest` follows the release catalog on Hugging Face. New models can be
added without updating the Python package. Each version points to a fixed model
revision, and downloaded weights are reused from the local cache. An existing
classifier stays on its resolved version; create a new one to pick up a newer release.

The catalog is cached after a successful lookup. Use `offline=True` with either
function to read only the cache. Network failures also fall back to the cached
catalog. Saved model folders load without looking up the catalog.

The hosted API resolves its own `latest`; `/v1/versions` lists models currently
available on that service, which may differ from those published on Hugging Face.

## Run on your computer

Use the same call with `mode="local"`:

```python
result = classifier.classify(
    "Great service!",
    choices=["positive", "neutral", "negative"],
    mode="local",
)
```

The first local call downloads the model. Later calls reuse the local copy.
Text stays on your computer. The constructor still requires an API key, but local
calls do not transmit or validate it. Use `device="cpu"` or `device="cuda"` at
construction to choose a device; the default automatically uses an available
NVIDIA GPU, otherwise the CPU. Apple GPU acceleration is not currently supported.

## Train from your own examples

Your DataFrame needs two columns: `text` and its correct `label`.

```python
import pandas as pd

df = pd.DataFrame({
    "text": ["Please close my account.", "I was charged twice."],
    "label": ["cancellation", "billing"],
})

fine_tuned = classifier.fine_tune(data=df)
result = fine_tuned.classify("Please cancel my account.")
print(result["results"][0]["selected"]["choice"])
```

The new classifier remembers the labels, runs locally, and leaves the original
unchanged. It stays in memory until you save it. Training text is not sent to
the API. The small example shows the format; use representative examples and
check predictions on separate examples that were not used for training.

A NumPy array also works: `classifier.fine_tune(data=df.to_numpy())`. It must
have two columns in this order: text, label. Both must contain non-empty strings.
Normally there must be at least two different labels. Optional `choices=` lets
you provide the full set explicitly, including a fallback such as `none`.

## Save and load

```python
fine_tuned.save("~/Downloads/my_classifier")

loaded = Classifier(
    api_key=os.environ["CLASSIFIER_API_KEY"],
    model_path="~/Downloads/my_classifier",
)
result = loaded.classify("Please cancel my account.")
```

Saving writes a complete model and its labels. It leaves the in-memory model
unchanged. The destination must be empty; existing models are never overwritten.
Loading restores the labels and uses your computer automatically. Keep the entire
saved folder together. After the required Python libraries are installed, a saved
model can run without downloading the original model again.

## Optional settings

Most users can keep the defaults. Pass these as named arguments when needed:

| Setting | Where | Meaning |
| --- | --- | --- |
| `mode="api"` or `"local"` | `classify` | Use the service or your computer |
| `version`, `domain` | Constructor or `classify` | Select a model |
| `epochs=1` | `fine_tune` | Passes through your training examples |
| `max_steps=1, grad_accum=1` | `fine_tune` | A quick one-step training check |
| `question="Which label fits?"` | `classify` or `fine_tune` | Describe the decision |
| `timeout=60` | Constructor | API timeout in seconds |
| `offline=True` | Constructor | Require local files and disable API calls |

API failures raise Requests exceptions. A 401 usually means the key is invalid;
a 429 means the request limit was reached. Respect `Retry-After` before retrying.
The client does not automatically retry or switch between the API and local mode.
Custom models run locally; they are not uploaded to the service by training or saving.

## Serve your saved model

Install the `serve` extra, then run:

```sh
theclassifier serve --model-path ~/Downloads/my_classifier
```

The local server listens at `http://127.0.0.1:8090`. It runs your model without
API keys, accounts, billing, or rate limits. Send requests directly:

```python
import requests

response = requests.post(
    "http://127.0.0.1:8090/v1/classify",
    json={
        "state": "Please close my account.",
        "questions": [{
            "question": "What does the customer want?",
            "choices": ["cancel account", "billing help", "technical support"],
        }],
    },
    timeout=60,
)
response.raise_for_status()
print(response.json())
```

Code and published model weights use Apache-2.0. See the technical paper for
research details and evaluation. Maintainers can find release checks in RELEASE.md.
