# mldash

Export trained ML models from notebooks to [ML-Dash](https://github.com/mrocha/ml-dash).

## Install

```bash
pip install mldash-sdk
```

Requires Python 3.8+.

## Quick Start

```python
import mldash

# One-time login (saved to ~/.config/mldash/credentials)
mldash.login()

# See your projects
mldash.list_projects()

# Set active project for this notebook (by name or ID)
mldash.init(project="Churn Analysis")

# Train your model
from sklearn.ensemble import RandomForestClassifier
model = RandomForestClassifier()
model.fit(X_train, y_train)

# Export — just model + name, everything else is resolved
mldash.export(model=model, name="Churn Predictor")
```

## Authentication

### `mldash.login()` — One-time setup

Run once per machine. You'll be prompted for your ML-Dash URL and API key:

```
>>> mldash.login()
ML-Dash URL: http://localhost:8000
Get your API key from: http://localhost:8000/developers/keys
API Key: ········
Authenticated with http://localhost:8000
Credentials saved to ~/.config/mldash/credentials
```

Credentials are stored locally at `~/.config/mldash/credentials` (chmod 600) and reused automatically.

You can also pass values directly (useful for CI or scripting):
```python
mldash.login(url="http://localhost:8000", api_key="mldash_xxx")
```

### `mldash.logout()`

```python
mldash.logout()  # removes stored credentials
```

### `mldash.whoami()`

```python
mldash.whoami()
# URL:     http://localhost:8000
# API Key: mldash_abcde...
# Project: Churn Analysis (id=3)
```

### Alternative auth methods

These work without calling `login()`:

**Environment variables:**
```bash
export MLDASH_URL=http://localhost:8000
export MLDASH_API_KEY=mldash_your_key_here
```

**Google Colab Secrets:**

Add `MLDASH_URL` and `MLDASH_API_KEY` to your Colab Secrets (key icon in sidebar).

## Browsing

### `mldash.list_projects()`

```python
mldash.list_projects()
# ID     Name                           Models   Datasets
# ----------------------------------------------------
# 1      Churn Analysis                 3        2
# 2      Imported Models                1        0
```

### `mldash.list_models()`

```python
mldash.list_models()                          # all models
mldash.list_models(project="Churn Analysis")  # filter by project
mldash.list_models(project=1)                 # filter by project ID
```

### `mldash.list_datasets()`

```python
mldash.list_datasets()                          # all datasets
mldash.list_datasets(project="Churn Analysis")  # filter by project
```

### `mldash.read_dataset()` — Download as DataFrame

```python
df = mldash.read_dataset(1)                    # by ID
df = mldash.read_dataset("my-dataset")         # by slug
df = mldash.read_dataset("alice/her-dataset")  # public dataset by username/slug
# Loaded dataset: 150 rows, 5 columns
```

Requires `pandas` (not included in SDK dependencies — install separately).

## Project Association

### `mldash.init()` — Set active project

Accepts a project name (string) or project ID (int):

```python
mldash.init(project="Churn Analysis")   # by name
mldash.init(project=3)                  # by ID

# All exports now go to that project
mldash.export(model=model1, name="Logistic v1")
mldash.export(model=model2, name="XGBoost v1")
```

The project is saved to credentials, so it persists across sessions.
Override per-export with the `project=` argument:

```python
mldash.export(model=model, name="Experiment", project="Other Project")
```

If no project is set, exports go to an auto-created **Imported Models** project.

## Usage

### Export with artifacts

```python
mldash.export(
    model=model,
    name="Sales Predictor",
    scaler=scaler,              # StandardScaler, MinMaxScaler, etc.
    encoder=encoder,            # OneHotEncoder, LabelEncoder, etc.
    label_map={"0": "no", "1": "yes"},
    features={"age": "numeric", "dept": "categorical", "review": "text"},
    target={"churn": "categorical"},
)
```

### `mldash.push()` — Alias for export

```python
mldash.push(model=model, name="My Model")  # same as export()
```

### Save to local ZIP (offline)

```python
mldash.save(
    model=model,
    name="My Model",
    path="./my_model.zip",
)
# Upload the ZIP manually via the ML-Dash web UI
```

### Auto-detection

The package auto-detects:
- **task_type** — classification or regression (from sklearn mixins)
- **framework** — sklearn, xgboost, lightgbm, etc. (from module path)
- **hyperparameters** — via `model.get_params()`
- **model_class** — e.g., `RandomForestClassifier`
- **n_features** — from `model.n_features_in_`
- **class_labels** — from `model.classes_`

## Typical Notebook Workflow

```python
# Cell 1: Setup (run once)
import mldash
mldash.login()
mldash.init(project="MAS 648 Final")

# Cell 2-N: Train models...
model = RandomForestClassifier(n_estimators=100)
model.fit(X_train, y_train)

# Cell N+1: Export
mldash.export(model=model, name="RF 100 trees")
```

## CLI

The SDK includes a command-line interface:

```bash
mldash login              # Authenticate (prompts for URL + API key)
mldash logout             # Remove stored credentials
mldash whoami             # Show current auth status
mldash connect            # Start local compute bridge for Studio
mldash setup              # Create managed Python venv (~/.mldash/venv/)
mldash install xgboost    # Install packages into managed venv
```

### `mldash connect`

Starts a local Python bridge so code written in ML-Dash Studio executes on your machine:

```bash
mldash connect                      # auto-select port
mldash connect --port 8765          # specific port
mldash connect --url http://...     # custom server URL
```

### `mldash setup`

Creates a managed Python environment at `~/.mldash/venv/` with common ML packages (pandas, numpy, scikit-learn, matplotlib, seaborn, mldash-sdk). The bridge auto-uses this environment.

```bash
mldash setup              # create environment
mldash setup --force      # recreate from scratch
```

## Errors

```python
from mldash import MLDashValidationError, MLDashAuthError, MLDashUploadError

try:
    mldash.export(model=model, name="Test")
except MLDashValidationError as e:
    print(f"Invalid input: {e}")
except MLDashAuthError as e:
    print(f"Auth failed: {e}")
except MLDashUploadError as e:
    print(f"Upload failed: {e}")
```
