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

# Overview

> Wood Wide AI provides a single API for training and running inference across six capabilities on tabular data. You upload a dataset, train a model by specifying a model type, and then run inference to get results.

Wood Wide AI supports six model types for tabular data: prediction, clustering, anomaly detection, embeddings, search, and factor analysis.

## Available Model Types

<CardGroup cols={2}>
  <Card title="Prediction" icon="bullseye-arrow" href="/capabilities/prediction">
    Supervised classification and regression on a target column.
  </Card>

  <Card title="Clustering" icon="object-group" href="/capabilities/clustering">
    Unsupervised grouping with human-readable cluster descriptions.
  </Card>

  <Card title="Anomaly Detection" icon="triangle-exclamation" href="/capabilities/anomaly">
    Identify unusual rows in your data.
  </Card>

  <Card title="Embeddings" icon="chart-scatter" href="/capabilities/embeddings">
    Generate dense vector representations of each row.
  </Card>

  <Card title="Search" icon="magnifying-glass" href="/capabilities/search">
    Find the most similar training-set row for each query row.
  </Card>

  <Card title="Factor Analysis" icon="chart-pie" href="/capabilities/factors">
    Discover the latent factors that explain variance in your data.
  </Card>
</CardGroup>

***

## General Workflow

Every capability follows the same three-step workflow:

1. **Upload a dataset** -- `POST /datasets` with a CSV or Parquet file.
2. **Train a model** -- `POST /models/train` with the `dataset_id`, a `model_name`, and the desired `model_type`.
3. **Run inference** — `POST /models/{model_id}/infer` with a CSV file to get results.

<CodeGroup>
  ```python Python theme={null}
  import os, time, requests

  api_key = os.getenv("WOODWIDE_API_KEY")
  base_url = "https://api.woodwide.ai"
  headers = {"Authorization": f"Bearer {api_key}"}

  # 1. Upload dataset
  with open("data.csv", "rb") as f:
      resp = requests.post(
          f"{base_url}/datasets",
          headers=headers,
          files={"file": ("data.csv", f, "text/csv")},
          data={"dataset_name": "my_data"},
      )
  dataset_id = resp.json()["dataset"]["id"]

  # 2. Train model (change model_type for different capabilities)
  resp = requests.post(
      f"{base_url}/models/train",
      headers=headers,
      json={
          "model_name": "my_model",
          "model_type": "prediction",  # or: clustering, anomaly, embedding, search, factors
          "dataset_id": dataset_id,
          "label_column": "target",    # required for prediction only
      },
  )
  model_id = resp.json()["model"]["id"]

  # 3. Wait for training
  while True:
      status = requests.get(
          f"{base_url}/models/{model_id}", headers=headers
      ).json()["status"]
      if status == "ready":
          break
      time.sleep(5)

  # 4. Run inference
  with open("data.csv", "rb") as f:
      resp = requests.post(
          f"{base_url}/models/{model_id}/infer",
          headers=headers,
          files={"file": ("data.csv", f, "text/csv")},
          data={"output_type": "json"},
      )
  print(resp.json()["data"])
  ```

  ```python Python (SDK) theme={null}
  import time
  from pathlib import Path
  from woodwide import WoodWide

  client = WoodWide()

  dataset = client.api.datasets.upload(
      file=Path("data.csv"),
      name="my_data",
      overwrite=True,
  )

  model = client.api.models.prediction.train(
      model_name="my_model",
      label_column="target",
      dataset_id=dataset.id,
      overwrite=True,
  )

  while True:
      model = client.api.models.retrieve(model.id)
      if model.training_status in {"COMPLETE", "FAILED"}:
          break
      time.sleep(5)

  if model.training_status == "FAILED":
      raise RuntimeError(model.err_msg)

  result = client.api.models.prediction.infer(
      model.id,
      dataset_id=dataset.id,
  )
  print(result.prediction)
  ```
</CodeGroup>

<Note>
  Training a second model on the same dataset -- even for a different capability -- is significantly faster than the first training run.
</Note>

***

## Supervised vs. Unsupervised Tasks

**Prediction** is the only supervised task -- it requires a `label_column` at training time and predicts that column at inference time on new data.

All other tasks (**clustering**, **anomaly detection**, **embeddings**, **search**, **factors**) are unsupervised. For these, it often makes sense to run inference on the same dataset you trained on. For example, to cluster your data, you would train a clustering model on that data and then run inference on the same dataset to get the cluster assignments. You can also run inference on different data, but the cluster assignments will be to the clusters learned from the training data. The same applies to the other unsupervised tasks -- see the section for each model capability for details.

## Next Steps

<CardGroup cols={2}>
  <Card title="API quickstart" icon="code" href="/api-reference/getting-started">
    Upload, train, and infer -- curl, JavaScript, Python, or the Python SDK tab.
  </Card>

  <Card title="Python SDK" icon="python" href="/sdk-quickstart">
    Install and configure the typed Python client.
  </Card>

  <Card title="CLI" icon="terminal" href="/cli">
    Script datasets, training, and inference with `wwai`.
  </Card>

  <Card title="Console" icon="game-console-handheld" href="https://console.woodwide.ai">
    Upload datasets, train models, and manage API keys in the UI.
  </Card>
</CardGroup>
