> ## Documentation Index
> Fetch the complete documentation index at: https://docs.synthefy.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

> Get predictions on tabular data, locally or through the hosted API.

Nori predicts continuous values from tabular data. You give it some labeled rows
as examples, and it predicts on new rows. No training, no fine-tuning required.

<Icon icon="github" /> [GitHub](https://github.com/Synthefy/synthefy-nori)  ·  🤗 [Hugging Face](https://huggingface.co/Synthefy/Nori)

There are two ways to use it:

<CardGroup cols={2}>
  <Card title="Run locally" icon="laptop" href="#local">
    Install the Python package and run inference on your own machine or server.
  </Card>

  <Card title="Call the API" icon="cloud" href="#api">
    Send a request to our hosted endpoint. No setup, no GPU required.
  </Card>
</CardGroup>

***

## Local

Install the open-source package:

```bash theme={null}
pip install synthefy-nori
```

Model weights download automatically from [Hugging
Face](https://huggingface.co/Synthefy/Nori) on first use, and no API key is
needed. It uses a GPU when one is available and falls back to CPU. Always name a
size — `"nori-30m"` (\~29.2M) or `"nori-6m"` (\~6M base). Omitting `model=` loads
the \~6M base without warning, so pass it explicitly (see [Models](#models)).

### Your first prediction

`NoriRegressor` is a scikit-learn–style estimator: `fit` stores your labeled
rows as context (there is no training step) and `predict` returns one value per
query row in a single forward pass.

```python theme={null}
from synthefy_nori import NoriRegressor

X_train = [[0.0, 1.0], [1.0, 0.0], [0.5, 0.5], [0.2, 0.8]]
y_train = [0.1, 0.9, 0.5, 0.3]
X_test  = [[0.3, 0.7], [0.8, 0.2]]

model = NoriRegressor(model="nori-30m")
model.fit(X_train, y_train)
print(model.predict(X_test))
```

```
[0.37, 0.72]
```

<Tip>
  Want one code path that runs locally **or** against the hosted API? Use the
  `synthefy` client's `SynthefyNoriClient(mode="auto")` (see the [API
  section](#api)). It runs locally when `synthefy-nori` is installed and falls
  back to the hosted endpoint otherwise.
</Tip>

### With a DataFrame

```python theme={null}
import pandas as pd
from synthefy_nori import NoriRegressor

df = pd.read_csv("data.csv")
target_col = "price"
feature_cols = [c for c in df.columns if c != target_col]

train = df.sample(frac=0.8, random_state=42)
test  = df.drop(train.index)

model = NoriRegressor(model="nori-30m").fit(train[feature_cols].values, train[target_col].values)
predictions = model.predict(test[feature_cols].values)
```

### Prediction intervals

Nori returns a full predictive distribution, so you get uncertainty for free.
Pass `output_type="quantiles"`:

```python theme={null}
q10, q50, q90 = model.predict(X_test, output_type="quantiles", quantiles=[0.1, 0.5, 0.9])
```

### Handle missing values

You don't need to fill in missing values beforehand. The model handles them
natively.

```python theme={null}
import numpy as np
from synthefy_nori import NoriRegressor

X_train = [[0.0, 1.0], [1.0, np.nan], [0.5, 0.5], [np.nan, 0.8]]
y_train = [0.1, 0.9, 0.5, 0.3]
X_test  = [[0.3, 0.7], [0.8, np.nan]]

model = NoriRegressor(model="nori-30m").fit(X_train, y_train)
print(model.predict(X_test))
```

```
[0.38, 0.71]
```

***

## API

The hosted API runs the same model on our infrastructure, so no installation or
GPU is required. Set up your API key in the [API key
guide](/setup/api_key#api-key-for-synthefy-nori).

From Python, use the [`synthefy` client](/nori/client). The same call works
either way: `mode="remote"` sends your rows to the hosted endpoint,
`mode="local"` runs the model on your own machine.

### Make a request

Send your labeled rows (`X_train`, `y_train`) and the rows you want to predict
(`X_test`) in a single call:

<CodeGroup>
  ```python Python theme={null}
  # pip install synthefy — see /nori/client for the full client guide
  import os
  from synthefy import SynthefyNoriClient

  client = SynthefyNoriClient(
      api_key=os.environ["SYNTHEFY_NORI_API_KEY"],
      model="nori-30m",
  )

  X_train = [[0.0, 1.0], [1.0, 0.0], [0.5, 0.5], [0.2, 0.8]]
  y_train = [0.1, 0.9, 0.5, 0.3]
  X_test  = [[0.3, 0.7], [0.8, 0.2]]

  print(client.predict(X_train, y_train, X_test))
  ```

  ```bash cURL theme={null}
  curl -X POST https://inference.baseten.co/predict \
    -H "Authorization: Bearer $SYNTHEFY_NORI_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "synthefy/nori-30m",
      "task": "regression",
      "X_train": [[0.0, 1.0], [1.0, 0.0], [0.5, 0.5], [0.2, 0.8]],
      "y_train": [0.1, 0.9, 0.5, 0.3],
      "X_test":  [[0.3, 0.7], [0.8, 0.2]]
    }'
  ```
</CodeGroup>

The cURL example posts to the generic, slug-routed inference endpoint and
authenticates with a Baseten API key (`Bearer` scheme).

**Request body**

| Field     | Required | Description                                                                                                                                                                                                 |
| --------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `model`   | Required | The model slug: `synthefy/nori-6m` (\~6M base), `synthefy/nori-30m` (\~29.2M), or `synthefy/nori-30m-thinking-medium`. Routes the request to the model; omitting it returns a `400`. See [Models](#models). |
| `task`    | Optional | `"regression"` or `"reg"`; defaults to `"regression"`. This is a regression-only deployment.                                                                                                                |
| `X_train` | Required | Context feature matrix, `n_context × n_features` (array of arrays of numbers).                                                                                                                              |
| `y_train` | Required | Context targets, aligned 1:1 with `X_train` rows (array of numbers).                                                                                                                                        |
| `X_test`  | Required | Query feature matrix, `n_query × n_features` (array of arrays of numbers).                                                                                                                                  |

`null`/`NaN` cells are allowed in `X_train` and `X_test` and are imputed
server-side.

### Request size limit

<Warning>
  A single request is capped at **100 MB**. Larger requests are rejected with
  `HTTP 413 Request Entity Too Large`.
</Warning>

The limit applies to the whole request, i.e. all of `X_train`, `y_train`, and
`X_test` together. Since size grows with rows × features, you only approach 100
MB with very large inputs (on the order of millions of values).

If you hit the limit, send fewer example rows, use fewer features, or split
`X_test` into smaller batches. You can reuse the same `X_train`/`y_train` across
those calls.

### Response

The client returns one value per row in `X_test` as a plain list:

```python theme={null}
[0.37, 0.72]
```

The underlying HTTP endpoint (used by the cURL example) returns the full
envelope on a `200` (values illustrative):

```json theme={null}
{
  "task": "regression",
  "predictions": [0.3861955995072203, 0.7150392187985302],
  "usage": {
    "prompt_tokens": 4,
    "completion_tokens": 3,
    "total_tokens": 7
  }
}
```

Read `predictions`, one value per `X_test` row, in order. The response also
includes a `usage` block (token counts) for API compatibility; it isn't
meaningful for a tabular model, so you can ignore it. (The Python client returns
just the `predictions` list.)

<Note>
  The first request after a scale-to-zero idle triggers a checkpoint download
  and warmup and can take \~60–90 seconds. Warm requests return in \~1–2 seconds.
</Note>

***

## Models

Select a model with the `model` parameter. The friendly names below work in both
the Python client (`SynthefyNoriClient`) and the `synthefy-nori` package
(`NoriRegressor`). Nori and Nori-30M run **locally or on the hosted API**;
**Nori Thinking is hosted-API only**.

| Model         | Params  | `model=` name                                        | Hosted-API id                       | Availability |
| ------------- | ------- | ---------------------------------------------------- | ----------------------------------- | ------------ |
| Nori (base)   | \~6M    | `"nori-6m"`                                          | `synthefy/nori-6m`                  | Local + API  |
| Nori-30M      | \~29.2M | `"nori-30m"`                                         | `synthefy/nori-30m`                 | Local + API  |
| Nori Thinking | \~29.2M | `"nori-30m-thinking"` / `"nori-30m-thinking-medium"` | `synthefy/nori-30m-thinking-medium` | **API only** |

* **`model=` name** — what you pass to `SynthefyNoriClient(model=…)` or
  `NoriRegressor(model=…)`.
* **Hosted-API id** — the value in the request body's `model` field on the raw
  HTTP endpoint (what the cURL example sends). The client fills it in for you
  from the friendly name; local inference doesn't use it.
* **Availability** — *Local + API* runs on your machine (weights download from
  Hugging Face on first use) or on the hosted endpoint. *API only* runs on the
  hosted endpoint only.

<Note>
  **Nori Thinking is hosted-API only.** It spends extra test-time compute to lift
  accuracy, is slower and premium-priced, and has no downloadable checkpoint. Only
  the **medium** budget is available today; both `"nori-30m-thinking"` and
  `"nori-30m-thinking-medium"` route to it. Selecting Thinking for local inference
  (`SynthefyNoriClient(mode="local"/"auto", …)` or
  `NoriRegressor(model="nori-30m-thinking-medium")`) raises an error pointing you
  at the hosted API. Use `mode="remote"`.
</Note>

The current, authoritative list of models your key can call (and their limits)
is returned live by `GET /forecasting-api/nori/available-models`, and shown per
model in the console.

```python theme={null}
# Hosted API — the friendly name selects the deployment
client = SynthefyNoriClient(
    api_key=os.environ["SYNTHEFY_NORI_API_KEY"],
    mode="remote",
    model="nori-30m-thinking-medium",  # Thinking: hosted-API only
)

# Local / package — the same name selects which checkpoint to download
from synthefy_nori import NoriRegressor
model = NoriRegressor(model="nori-30m")   # base and nori-30m run locally; Thinking does not
```

Always name a size: `"nori-30m"` (\~29.2M) or `"nori-6m"` (\~6M base). The
`synthefy` client **requires** it and raises if you omit it; `NoriRegressor`
falls back to the \~6M base silently, so pass it there too. In **local** mode the
selector picks the checkpoint (downloaded from Hugging Face on first use). The
raw Hosted-API slug (e.g. `synthefy/nori-30m`) is also accepted by the client
and is what the cURL endpoint expects in the `model` field.

***

## Next steps

<CardGroup cols={2}>
  <Card title="Python Client" icon="plug" href="/nori/client">
    Auth, retries, DataFrames and text columns, handled for you.
  </Card>

  <Card title="Examples" icon="code" href="/nori/examples">
    End-to-end worked examples on real datasets.
  </Card>

  <Card title="Missing Values & Imputation" icon="table-cells" href="/nori/missing-values">
    Pass NaNs straight through, with no pre-filling required.
  </Card>

  <Card title="Explainability" icon="magnifying-glass-chart" href="/nori/explainability">
    SHAP values, feature interactions, and partial dependence.
  </Card>

  <Card title="Run it in your cloud" icon="cloud" href="/nori/sagemaker">
    Deploy on Amazon SageMaker, or call Nori from Snowflake SQL.
  </Card>

  <Card title="Product page" icon="globe" href="https://www.synthefy.com/product/tabular">
    Learn more about Synthefy Nori (Tabular).
  </Card>
</CardGroup>
