Metadata-Version: 2.4
Name: modulearn
Version: 0.1.0
Summary: A visual, Unreal-Blueprints-style node-graph editor for building and launching ML training runs.
Project-URL: Homepage, https://github.com/IsaiahKoamalu/modulearn
Project-URL: Source, https://github.com/IsaiahKoamalu/modulearn
Author: Isaiah Broderson
License: MIT
License-File: LICENSE
Keywords: fastapi,machine-learning,node-graph,training,visual-programming
Classifier: Development Status :: 3 - Alpha
Classifier: Framework :: FastAPI
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: >=3.10
Requires-Dist: fastapi>=0.110
Requires-Dist: pydantic>=2.0
Requires-Dist: uvicorn>=0.29
Provides-Extra: dev
Requires-Dist: build; extra == 'dev'
Requires-Dist: pytest>=7; extra == 'dev'
Requires-Dist: twine; extra == 'dev'
Description-Content-Type: text/markdown

# ModuLearn

A visual, [Unreal-Blueprints](https://dev.epicgames.com/documentation/en-us/unreal-engine/blueprints-visual-scripting-in-unreal-engine)-style
node-graph editor for building and launching machine-learning training runs.
Drop **Dataset → Model → Train** nodes on a canvas, wire **hyperparameters**,
**loss** and **feature transforms** into them, hit ▶ Train, and watch the learning
curve live on the graph. No forms, no drift between the UI and the code it runs.

> **ModuLearn** is a working name — you assemble training runs from modular nodes and
> learn from the live curve. Rename the package/repo freely; nothing depends on the name.

<!-- A screenshot or GIF of the editor goes well here. -->

## Why

Most training UIs are flat forms that slowly rot out of sync with the code behind
them. ModuLearn inverts that: your Python is the single source of truth. You *declare*
what you can train once, in a `Registry`, and the entire editor — palette, typed
wiring rules, live validation, launch — is generated from it. Wire something the
backend can't accept and it simply won't connect.

## Install

```bash
pip install -e .          # fastapi + uvicorn + pydantic
modulearn demo            # serve the bundled editor at http://localhost:8000
```

`modulearn demo` is a complete, **dependency-free** editor (its "trainer" is a toy
loss curve) so you can click around immediately. Once you've built your own app,
serve it the same way:

```bash
modulearn run myproject.py        # serves the `app` you built with create_app
modulearn run myproject.py:editor # ...or a differently-named app / factory
modulearn --help
```

Swap `on_train` for your real training loop and nothing else changes. (The
equivalent source file lives at [`examples/quickstart.py`](examples/quickstart.py)
if you'd rather run it directly with `python`.)

## The whole integration is two things

```python
from modulearn import Registry, Param, create_app

reg = Registry()

reg.add_dataset("iris", title="Iris", kind="tabular",
                features=[...], targets=["species"])
reg.add_model("mlp", title="MLP", requires_kind="tabular",
              params=[Param("hidden", "hidden layers", "int_list", [64, 32])])
reg.add_hyperparameter("lr", label="learning rate", default=1e-3, min=1e-6, max=1)
reg.add_loss([Param("loss", "kind", "enum", "mse", choices=["mse", "cross_entropy"])])

def on_train(compiled, reporter):
    # compiled.dataset, .model, .model_params, .hyperparameters, .loss_params, .transforms
    reporter.state(epochs=100)
    for e in range(100):
        reporter.metric(epoch=e, train=..., val=...)   # drives the live chart
        reporter.state(epoch=e, best_val=...)
    reporter.state(phase="done", test_score=...)

app = create_app(reg, on_train, title="My Project")
```

1. **A `Registry`** — declare datasets, models, hyperparameters, a loss, and
   optional feature transforms. Each hyperparameter you add automatically grows a
   matching, type-checked input on the Train sink.
2. **`on_train(compiled, reporter)`** — your training loop. `compiled` is a
   fully-validated [`CompiledGraph`](modulearn/compiler.py); `reporter` publishes
   progress the editor polls (see the state contract below).

## How it fits together

```
 registry.py   ── you declare nodes ──►  catalog (GET /api/nodes)
      │                                        │
      ▼                                        ▼
 compiler.py   ◄── canvas JSON ────────  static/ (custom canvas engine)
      │  type-checks every wire, runs semantic checks
      ▼
 CompiledGraph ──►  your on_train(compiled, reporter)  ──►  runs/<id>/{state,metrics}.json
                                                                   │
                                                    editor polls ◄─┘  (live panel + chart)
```

- **Typed ports.** Links carry a family (`dataset`, `model`, `loss`, `run`) or a
  field-specific scalar subtype (`scalar/lr`), so a learning-rate value fits the
  `lr` input and *never* `epochs` — enforced both client-side and in the compiler.
- **All-or-nothing compile.** `compile_graph` collects every structural, type and
  semantic error and raises them together, so the UI flags all bad wires at once.
- **Composable transforms.** Chain `Dataset → Transform → … → Model`; the compiler
  walks the chain into `compiled.transforms`. Mark a transform `live=False` to show
  it in the palette but have the compiler refuse it until your backend is ready.
- **Stateless live window.** Training runs in a background thread and persists to
  `runs/<id>/`. Closing the browser never stops a run; reopening shows true state.

## The state contract

Your `on_train` reports through `reporter`, and the editor reads these keys:

| call | keys the UI understands |
|------|-------------------------|
| `reporter.state(**kw)` | `phase` (`running`/`done`/`error`), `epoch`, `epochs`, `best_val`, `test_score`, `error` |
| `reporter.metric(**row)` | `epoch`, `train`, `val` → the live learning curve |

Anything else you write is stored and returned by the API, just not charted.

## Editor niceties

- Searchable palette with collapsible category dropdowns; `⌘K` / `/` to focus,
  Enter to drop the first match.
- Wires colored by type, with flowing pulses that speed up on the edges feeding a
  running Train node; ports glow while you drag a compatible connection.
- Canvas persists to `localStorage`; reload/fork any past run's blueprint.
- All motion respects `prefers-reduced-motion`.

## Layout

```
modulearn/
  registry.py    the declarative surface your app fills in
  compiler.py    graph JSON -> validated CompiledGraph (pure, unit-testable)
  server.py      create_app(): FastAPI factory + background job runner
  cli.py         the `modulearn` command (demo / run)
  demo.py        the app `modulearn demo` serves
  static/        graph.html, graph.js (app), graph-engine.js (canvas engine)
examples/
  quickstart.py  a complete, dependency-free editor
```

## License

MIT (see [LICENSE](LICENSE)). The canvas node-graph engine
(`static/graph-engine.js`) is our own, built from scratch — no third-party
graph library.
