Metadata-Version: 2.5
Name: lumma-fev
Version: 0.1.1
Summary: Typed decisions with probabilities from FrontiersMind Lumma-Fev models: local inference, a TypeSafe-compatible API server and a client.
Project-URL: Homepage, https://www.frontiersmind.ai/
Project-URL: Models, https://huggingface.co/FrontiersMind
Author-email: FrontiersMind <support@frontiersmind.ai>
License-Expression: Apache-2.0
License-File: LICENSE
License-File: NOTICE
Keywords: classification,decision-model,frontiersmind,lumma,typesafe
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: >=3.10
Requires-Dist: httpx>=0.27
Requires-Dist: torch>=2.4
Requires-Dist: transformers<6,>=5.4
Provides-Extra: serve
Requires-Dist: fastapi>=0.110; extra == 'serve'
Requires-Dist: pydantic>=2.6; extra == 'serve'
Requires-Dist: uvicorn>=0.29; extra == 'serve'
Description-Content-Type: text/markdown

# lumma-fev

Run FrontiersMind **Lumma-Fev** decision models: give a document (the *state*) and typed questions, and get a
probability distribution for every question in one forward pass. No text is generated, so there is nothing to parse.

- `lumma_fev.load()`: run a model locally (cuda, mps or cpu).
- `lumma-fev-serve`: a TypeSafe-compatible HTTP API (`POST /v1/systemone`), so existing TypeSafe clients work by
  changing their base URL.
- `lumma_fev.Client`: a small client for that API.

Models: [FrontiersMind/lumma-fev-0.1b](https://huggingface.co/FrontiersMind/lumma-fev-0.1b) (default) and other
`FrontiersMind/lumma-fev-*` repos.

## Install

```bash
pip install lumma-fev              # local inference and the client
pip install "lumma-fev[serve]"     # plus the API server
```

## Run locally

```python
import lumma_fev

model = lumma_fev.load()           # FrontiersMind/lumma-fev-0.1b; load("FrontiersMind/<repo>", revision=...) for others

answers = model.decide(
    state="I was charged twice for my March invoice. Please refund one of them.",
    questions={
        "billing": {"type": "noul", "instructions": "Is this about billing?"},
        "team": {"type": "choice", "instructions": "Which team should handle this?",
                 "criteria": {"billing": "Payments and refunds", "shipping": "Delivery problems", "technical": "Bugs and outages"}},
        "urgency": {"type": "score", "instructions": "How urgent is this?",
                    "criteria": ["can wait", "this week", "today"]},
    },
)
# {"billing": {"noul": 0.97}, "team": {"choice": "billing", "confidence": ..., "probabilities": {...}},
#  "urgency": {"score": ..., "confidence": ..., "legend": [...], "probabilities": {...}}}
```

`load(model, revision=None, device=None, dtype=None)` picks cuda, then mps, then cpu, and uses bf16 on accelerators
and fp32 on cpu. The same model loads with transformers alone:
`AutoModel.from_pretrained("FrontiersMind/lumma-fev-0.1b", trust_remote_code=True)`.

## Serve an API

```bash
lumma-fev-serve --model FrontiersMind/lumma-fev-0.1b --host 0.0.0.0 --port 8000
```

| Flag | Default | |
|---|---|---|
| `--model` | `FrontiersMind/lumma-fev-0.1b` | Hub id or local folder |
| `--revision` | latest | branch, tag or commit |
| `--name` | repo name | model name reported by the API |
| `--host`, `--port` | `127.0.0.1`, `8000` | use `0.0.0.0` to accept other machines |
| `--device`, `--dtype` | auto | `cuda`/`mps`/`cpu`, `bf16`/`fp32` |
| `--api-key` | `$LUMMA_FEV_API_KEY` | when set, requests need `Authorization: Bearer <key>` |
| `--cors` | off | allow browser pages on any origin |

Endpoints: `POST /v1/systemone`, `GET /v1/models`, `GET /health`. Requests run one at a time.

```bash
curl -s localhost:8000/v1/systemone -H 'content-type: application/json' -d '{
  "state": "I was charged twice. Please fix this ASAP.",
  "questions": {"billing": {"type": "noul", "instructions": "Is this ticket about billing?"}}
}'
# {"model": "lumma-fev-latest", "answers": {"billing": {"noul": 0.98}}, "usage": {"input_tokens": 31, "output_tokens": 9}}
```

## Call it from Python

```python
from lumma_fev import Client

with Client("http://127.0.0.1:8000", api_key=None) as client:
    print(client.decide("I was charged twice.", {"billing": {"type": "noul", "instructions": "Is this about billing?"}}))
    print(client.models())
```

`client.system_one(...)` returns the full response (model, answers, usage); errors raise `lumma_fev.LummaFevError`
with the HTTP status and detail.

The [TypeSafe SDK](https://pypi.org/project/typesafe-sdk/) works against the same server:

```python
from typesafe_sdk import Noul, TypeSafeClient

with TypeSafeClient(api_key="local", base_url="http://127.0.0.1:8000") as ts:
    result = ts.system_one(state="I was charged twice.", questions={"billing": Noul(instructions="Is this about billing?")})
    print(result.nouls["billing"].noul)
```

The SDK always sends an API key; any value works when the server has no `--api-key`.

## Questions and answers

| Type | Criteria | Answer |
|---|---|---|
| `noul` | optional `{"true": ..., "false": ...}` | `noul`: probability of yes |
| `choice` | `{name: description or null}`, 1–255 options | `choice`, `confidence`, `probabilities` by name |
| `score` | ordered list of 1–255 levels | `score` (expected level), `confidence`, `legend`, `probabilities` by level |

`state` and `instructions` can be text or any JSON value. Each question reads the state and its own instructions and
options only, so questions never influence each other. Long states are truncated to the model's context (see the model
card).

## License

Apache-2.0. See `LICENSE` and `NOTICE`.
