aura-lang 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +154 -0
- data/LICENSE +21 -0
- data/README.md +120 -0
- data/Rakefile +59 -0
- data/aura-lang.gemspec +29 -0
- data/bin/aura +151 -0
- data/examples/assistant.aura +12 -0
- data/examples/chatbot.aura +7 -0
- data/examples/hello.aura +10 -0
- data/examples/mnist_classifier.aura +36 -0
- data/examples/sentiment.aura +13 -0
- data/examples/transfer_api.aura +25 -0
- data/lib/aura/analyzer.rb +125 -0
- data/lib/aura/codegen.rb +636 -0
- data/lib/aura/diagnostics.rb +86 -0
- data/lib/aura/docker.rb +81 -0
- data/lib/aura/emitter.rb +61 -0
- data/lib/aura/parser.rb +208 -0
- data/lib/aura/transformer.rb +152 -0
- data/lib/aura/vercel.rb +88 -0
- data/lib/aura/version.rb +8 -0
- data/lib/aura.rb +125 -0
- metadata +158 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: b5a53033716e3d07a59c7296c6328f45c7c30a9e39d501a7a5d6ff0593b7d33f
|
|
4
|
+
data.tar.gz: 1e4d6fa383dde613cb0d900fd5d8fedcacfcfa865bb357a58eb17a5dc18d852b
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: cede94d08727f5ff825ced664ad5ff14854919b9bb2b071f0d5099640da4faecedf70592a4c426f08bcf40e76f59839b9c7a315d95fb00bb4168724ef979867c
|
|
7
|
+
data.tar.gz: 7428d7086f65d52ab169e0ddff72004ef696e451d941105cabfb444fb119b3c0ac24dfece326dacb42ea1053490622cdff4f554a5ca90617ada6667161f007b4
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to Aura are documented here. The format is based on
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/), and the project aims to follow
|
|
5
|
+
[Semantic Versioning](https://semver.org/).
|
|
6
|
+
|
|
7
|
+
## [1.3.0]
|
|
8
|
+
|
|
9
|
+
A correctness + feature release driven by a full-project audit.
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
- **Conv model without an explicit `input shape` no longer emits uncompilable
|
|
13
|
+
Ruby** (`Conv2d.new(, …)`); channels default to 1.
|
|
14
|
+
- **`train`/`evaluate` on an LLM or text model is now a compile-time error**
|
|
15
|
+
(it previously generated `<model>_model.train` → NameError).
|
|
16
|
+
- **Transfer models use the correct module `TorchVision::Models`** (was the
|
|
17
|
+
non-existent `Torchvision::Models`).
|
|
18
|
+
- **Multiple `environment` blocks are rejected** (they redefined `AuraConfig`).
|
|
19
|
+
- **Torch inference routes guard a missing input key** (`halt 400`) and rescue
|
|
20
|
+
errors as JSON instead of 500-ing with a stack trace.
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
- **Sequence layers**: `layer embedding vocab:, dim:`, `layer lstm units:`,
|
|
24
|
+
`layer gru units:` (RNNs take the last timestep). Best-effort — compile/stub
|
|
25
|
+
verified, validate against your torch-rb.
|
|
26
|
+
- **LLM configuration**: `model x from openai "id" do system "…"; temperature 0.7;
|
|
27
|
+
max_tokens 500 end`, threaded into the OpenAI/Ollama request.
|
|
28
|
+
- **Output post-processing**: `predict(x) as :label` returns class indices
|
|
29
|
+
(argmax) instead of raw logits.
|
|
30
|
+
- **Automatic `/health` endpoint** for every served app.
|
|
31
|
+
- **CSV datasets**: `train m on "data.csv"` reads a CSV (last column = label).
|
|
32
|
+
- **Type-aware Dockerfiles**: Torch apps now install `torch-rb torchvision
|
|
33
|
+
red-datasets` and include LibTorch setup guidance; LLM/text apps stay slim.
|
|
34
|
+
|
|
35
|
+
### Changed
|
|
36
|
+
- Version bumped to 1.3.0. Suite grew to 65 examples (incl. execution tests for
|
|
37
|
+
sequence models, CSV training, `/health`, and `as :label`).
|
|
38
|
+
|
|
39
|
+
> Note: new Torch ops (RNNs, scheduler args, CIFAR loader, the Torch Dockerfile)
|
|
40
|
+
> are compile/stub-verified, not run against LibTorch in CI.
|
|
41
|
+
|
|
42
|
+
## [1.2.2]
|
|
43
|
+
|
|
44
|
+
### Fixed
|
|
45
|
+
- **Inference now works for CNN models.** Routes reshape the JSON payload to the
|
|
46
|
+
model's input dims via `aura_input_tensor` and run under `eval` + `no_grad`,
|
|
47
|
+
instead of passing a bare array straight into a Conv2d (which crashed).
|
|
48
|
+
- **LR schedulers get correct constructor arguments** per type (`StepLR`,
|
|
49
|
+
`ExponentialLR` → `gamma`, `CosineAnnealingLR` → `t_max`) instead of a
|
|
50
|
+
hard-coded `step_size:`.
|
|
51
|
+
- **Route paths and HTTP verbs are validated/escaped** — paths are emitted via
|
|
52
|
+
`inspect` (no broken Ruby on a `'` in the path); unknown verbs are rejected at
|
|
53
|
+
compile time.
|
|
54
|
+
|
|
55
|
+
### Added / changed
|
|
56
|
+
- **Training is separated from serving.** Training and evaluation only run in
|
|
57
|
+
training mode (`aura train <file>`, i.e. `AURA_TRAIN=1`); `aura run` loads
|
|
58
|
+
weights and serves without retraining on every boot.
|
|
59
|
+
- **Unknown LLM providers are rejected** at compile time (previously any provider
|
|
60
|
+
silently became OpenAI). Supported: `openai`, `ollama`.
|
|
61
|
+
- **Hardened LLM clients** — connection/read timeouts, non-2xx handling, and
|
|
62
|
+
rescue around the request.
|
|
63
|
+
- **Hardened auth** — constant-time bearer-token comparison
|
|
64
|
+
(`Rack::Utils.secure_compare`) and an explicit refusal when `AURA_API_TOKEN`
|
|
65
|
+
is unset.
|
|
66
|
+
- **`environment device`** is honored: `device :cpu` forces CPU; otherwise the
|
|
67
|
+
app auto-selects CUDA when available.
|
|
68
|
+
- New `aura train` CLI command; expanded runtime tests now execute the training
|
|
69
|
+
loop (stubbed Torch) and assert training is skipped while serving.
|
|
70
|
+
|
|
71
|
+
## [1.2.1]
|
|
72
|
+
|
|
73
|
+
### Fixed
|
|
74
|
+
- Inline and trailing `# ...` comments are stripped before parsing (previously
|
|
75
|
+
only full-line comments were). `#` inside string literals is preserved.
|
|
76
|
+
- Numeric literals support scientific notation (`1e-4`) and negative values;
|
|
77
|
+
string literals support escaped quotes (`\"`).
|
|
78
|
+
- Generated apps start the web server under `aura run` (emit `set :run, true`).
|
|
79
|
+
- Use the correct Torch CUDA API (`Torch::CUDA.available?`).
|
|
80
|
+
- Route handlers read the request payload using the key named in
|
|
81
|
+
`model.predict(<key>)` rather than a fixed key.
|
|
82
|
+
|
|
83
|
+
### Added
|
|
84
|
+
- Complete training and evaluation loops: forward/backward/optimizer step,
|
|
85
|
+
optional accuracy metric, learning-rate scheduler stepping, and an automatic
|
|
86
|
+
`save weights` call after training.
|
|
87
|
+
- Dataset loading for the bundled red-datasets sets (MNIST, Fashion-MNIST,
|
|
88
|
+
CIFAR), with a clear error and extension point for other sources.
|
|
89
|
+
Environment variables are loaded from `.env` via dotenv.
|
|
90
|
+
- Transfer-learning models apply `freeze` / `unfreeze all` to the pretrained
|
|
91
|
+
backbone and build a classification head from `output units:`.
|
|
92
|
+
- Bearer-token authentication for `authenticate with`
|
|
93
|
+
(`Authorization: Bearer <token>`).
|
|
94
|
+
- Semantic validation for duplicate model names and duplicate routes.
|
|
95
|
+
- Vercel deployment for LLM-only apps via `aura deploy <file> --target vercel`
|
|
96
|
+
(generates `vercel.json` and a Rack entrypoint); Torch apps are directed to
|
|
97
|
+
the container/`Dockerfile` path.
|
|
98
|
+
- Runtime test suite that boots generated apps and exercises their routes.
|
|
99
|
+
|
|
100
|
+
### Changed
|
|
101
|
+
- The gem version is sourced from `Aura::VERSION` (single source of truth).
|
|
102
|
+
- Added `rake build` / `rake release` and `rake bump:patch|minor|major`.
|
|
103
|
+
- The release workflow runs the full test suite, triggers on version tags, and
|
|
104
|
+
publishes to RubyGems via Trusted Publishing (OIDC).
|
|
105
|
+
|
|
106
|
+
## [1.2.0]
|
|
107
|
+
|
|
108
|
+
This release makes the framework actually implement what it has long advertised.
|
|
109
|
+
Previously the transpiler parsed the DSL but emitted little real code (models
|
|
110
|
+
compiled to an identity `forward`, training/routes/datasets produced nothing,
|
|
111
|
+
and `aura deploy` referenced a method that did not exist). The compiler has been
|
|
112
|
+
rebuilt into a real, modular pipeline.
|
|
113
|
+
|
|
114
|
+
### Added
|
|
115
|
+
- **Real neural-network code generation.** `neural_network` models now compile
|
|
116
|
+
to `Torch::NN::Module` subclasses with a genuine `forward` pass. Supported
|
|
117
|
+
layers: `input shape(...)` (with optional `do ... end` preprocessing block),
|
|
118
|
+
`input text`, `conv2d`, `maxpool2d`, `batchnorm`, `flatten`, `dense`,
|
|
119
|
+
`dropout`, and `output`. Tensor shapes are tracked so `Conv2d` in-channels and
|
|
120
|
+
`Linear` in-features are computed automatically.
|
|
121
|
+
- **Real training loops.** `train` emits optimizer, loss criterion, optional LR
|
|
122
|
+
scheduler, and an epoch loop. New options: `batch_size`, `metrics`.
|
|
123
|
+
- **Web serving.** `route` blocks compile to classic-Sinatra handlers (with
|
|
124
|
+
`format :json`, `authenticate with`), and `run web on port:` boots the server.
|
|
125
|
+
- **LLM models.** `model <name> from openai "..."` / `from ollama "..."` compile
|
|
126
|
+
to HTTP client methods (no training loop emitted for LLM models).
|
|
127
|
+
- **`evaluate <model> on "..."`**, **environment config** (`class AuraConfig`),
|
|
128
|
+
**dataset** declarations, and model persistence (`save weights to` /
|
|
129
|
+
`load weights from`).
|
|
130
|
+
- **`Aura.parse`** public entry point and **`Aura.build_docker`** (backs
|
|
131
|
+
`aura deploy`, generating a `Dockerfile` + `.dockerignore`).
|
|
132
|
+
- **Diagnostics.** Parse failures become `Aura::ParseError` with line/column and
|
|
133
|
+
a source snippet; a semantic pass raises `Aura::SemanticError` for references
|
|
134
|
+
to undefined models in `train`/`route`/`evaluate`.
|
|
135
|
+
- **Comment support** (`# ...`) in `.aura` files, plus tolerance for blank lines.
|
|
136
|
+
- New tests: `test_examples.rb` (every example/scaffold transpiles to compilable
|
|
137
|
+
Ruby) and `test_diagnostics.rb`.
|
|
138
|
+
|
|
139
|
+
### Changed
|
|
140
|
+
- The compiler was split from a single `lib/aura.rb` into focused modules under
|
|
141
|
+
`lib/aura/` (`parser`, `transformer`, `analyzer`, `codegen`, `emitter`,
|
|
142
|
+
`diagnostics`, `docker`, `version`).
|
|
143
|
+
- Code generation uses an indentation-aware emitter instead of string
|
|
144
|
+
concatenation, and classic Sinatra (`require "sinatra"`).
|
|
145
|
+
- `aura init` now scaffolds a parseable app and reports `Created Aura project`;
|
|
146
|
+
`aura run <missing>` writes a starter template; CLI output is ASCII-only.
|
|
147
|
+
- `torch-rb` is now an **optional** dependency (required only to run models), so
|
|
148
|
+
the gem installs and CI passes without LibTorch present.
|
|
149
|
+
- Version is sourced from a single `Aura::VERSION` constant (the CLI banner no
|
|
150
|
+
longer drifts from the gem version).
|
|
151
|
+
|
|
152
|
+
### Removed
|
|
153
|
+
- Stray scratch files committed at the repo root and a checked-in `*.gem` build
|
|
154
|
+
artifact.
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025-2026 John V Teixido
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# 🌟 Aura: The Advanced AI Web Framework (v1.3.0)
|
|
2
|
+
|
|
3
|
+
**A [RootSpace.app](https://rootspace.app) Product**
|
|
4
|
+
**Founded and Developed by [John V. Teixido](https://github.com/johnvteixido)**
|
|
5
|
+
|
|
6
|
+
[](https://ruby-lang.org)
|
|
7
|
+
[](https://rubygems.org/gems/aura-lang)
|
|
8
|
+
|
|
9
|
+
Aura is a **professional-grade AI Web Framework** that allows you to build, train, and deploy advanced AI models in a single declarative file. By combining **Torch-rb**, **Torchvision**, and **Sinatra**, Aura bridges the gap between deep learning research and production web services.
|
|
10
|
+
|
|
11
|
+
## 🚀 Key Features
|
|
12
|
+
- **Layers**: `conv2d`, `maxpool2d`, `batchnorm`, `dropout`, `dense`, plus
|
|
13
|
+
sequence layers `embedding`, `lstm`, and `gru`.
|
|
14
|
+
- **Transfer Learning**: Bootstrap with pre-trained architectures (ResNet, etc.)
|
|
15
|
+
via `transfer from :model_name`, with `freeze`/`unfreeze` and a new head.
|
|
16
|
+
- **Advanced Training**: Declarative LR schedulers (`StepLR`, `ExponentialLR`,
|
|
17
|
+
`CosineAnnealingLR`), optimizers, metrics, and a `train`/`serve` split.
|
|
18
|
+
- **Datasets**: built-in MNIST / Fashion-MNIST / CIFAR loaders, plus **CSV**
|
|
19
|
+
(`train m on "data.csv"`).
|
|
20
|
+
- **LLMs**: `from openai` / `from ollama` with a config block (`system`,
|
|
21
|
+
`temperature`, `max_tokens`).
|
|
22
|
+
- **Serving**: typed JSON routes, bearer-token auth, `predict(...) as :label`
|
|
23
|
+
post-processing, and an automatic `/health` endpoint.
|
|
24
|
+
- **Model Persistence**: native `save` / `load` weight primitives.
|
|
25
|
+
- **Deployment**: type-aware Dockerfiles and a Vercel target (`aura deploy`).
|
|
26
|
+
|
|
27
|
+
## 🛠️ Installation
|
|
28
|
+
```bash
|
|
29
|
+
gem install aura-lang
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
> **Torch is optional.** Parsing, transpiling (`aura check`), and building
|
|
33
|
+
> (`aura build` / `aura deploy`) work out of the box. Training and running
|
|
34
|
+
> models additionally require [`torch-rb`](https://github.com/ankane/torch.rb)
|
|
35
|
+
> and LibTorch: `gem install torch-rb`.
|
|
36
|
+
|
|
37
|
+
### 🔨 Local Installation (From Source)
|
|
38
|
+
If you are developing Aura or want to use the latest unreleased version:
|
|
39
|
+
```bash
|
|
40
|
+
git clone https://github.com/johnvteixido/aura-lang
|
|
41
|
+
cd aura-lang
|
|
42
|
+
gem build aura-lang.gemspec
|
|
43
|
+
gem install ./aura-lang-1.3.0.gem
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## 🧠 Example: Transfer Learning Image API
|
|
47
|
+
Build a professional Image Classifier in seconds:
|
|
48
|
+
|
|
49
|
+
```aura
|
|
50
|
+
# Scaffolding a production vision API
|
|
51
|
+
environment production do
|
|
52
|
+
device :cuda
|
|
53
|
+
log_level :info
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
model vision transfer from :resnet18 do
|
|
57
|
+
# Fine-tune the head while keeping features frozen
|
|
58
|
+
freeze until :layer_4
|
|
59
|
+
output units: 10, activation: :softmax
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
train vision on "imagenet-subset" do
|
|
63
|
+
epochs 20
|
|
64
|
+
optimizer :adam, learning_rate: 0.0001
|
|
65
|
+
scheduler :step_lr # Advanced LR scheduling
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
route "/v1/classify" post do
|
|
69
|
+
authenticate with :token
|
|
70
|
+
output prediction from vision.predict(image)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
run web on port: 8080
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
> **What runs out of the box:** `aura check` / `build` / `deploy` transpile this
|
|
77
|
+
> to a standalone Sinatra app with no extra setup. **Training and serving** need
|
|
78
|
+
> [`torch-rb`](https://github.com/ankane/torch.rb) + LibTorch installed.
|
|
79
|
+
> Built-in dataset loading covers the [red-datasets](https://github.com/red-data-tools/red-datasets)
|
|
80
|
+
> sets (MNIST / Fashion-MNIST / CIFAR); for any other dataset, the generated
|
|
81
|
+
> loader raises with a clear hook so you can plug your own in.
|
|
82
|
+
|
|
83
|
+
## 🏗️ Commands
|
|
84
|
+
- `aura init <name>`: Scaffold a new production project.
|
|
85
|
+
- `aura train <file>`: Train the models, persist weights, then exit.
|
|
86
|
+
- `aura run <file>`: Serve the app (loads saved weights; does **not** retrain).
|
|
87
|
+
- `aura check <file>`: Transpile and preview the generated Ruby.
|
|
88
|
+
- `aura build <file>`: Export to standalone Ruby.
|
|
89
|
+
- `aura deploy <file>`: Generate a production `Dockerfile` (add `--target vercel` for LLM-only apps).
|
|
90
|
+
- `aura console`: Interactive debugging with app context.
|
|
91
|
+
|
|
92
|
+
> Training and serving are separate: `aura train` runs the `train`/`evaluate`
|
|
93
|
+
> blocks and saves weights; `aura run` loads those weights and serves, so the
|
|
94
|
+
> server never retrains on boot.
|
|
95
|
+
|
|
96
|
+
## 🚢 Deployment
|
|
97
|
+
- **Torch apps** (neural networks, transfer learning, training) run on a
|
|
98
|
+
container host (Fly.io, Render, Cloud Run; GPU via Modal or Replicate).
|
|
99
|
+
`aura deploy <file>` generates a production `Dockerfile`. Torch model servers
|
|
100
|
+
need LibTorch and a long-lived process, so they are not suited to serverless
|
|
101
|
+
platforms.
|
|
102
|
+
- **LLM-only / text apps** (`from openai` / `from ollama`) run on Vercel's Ruby
|
|
103
|
+
runtime via `aura deploy <file> --target vercel`, or on any container host.
|
|
104
|
+
|
|
105
|
+
## 📈 Roadmap
|
|
106
|
+
- [x] CNN & Convolutional Layers
|
|
107
|
+
- [x] Model Persistence (v1.1)
|
|
108
|
+
- [x] Transfer Learning & Schedulers (v1.2)
|
|
109
|
+
- [x] Sequence layers (Embedding/LSTM/GRU), LLM config, CSV datasets (v1.3)
|
|
110
|
+
- [ ] Distributed Training (v1.4)
|
|
111
|
+
- [ ] Native RAG (Retrieval Augmented Generation) Primitives (v1.5)
|
|
112
|
+
|
|
113
|
+
## ☕ Support Aura Development
|
|
114
|
+
Aura is an open-source project by RootSpace.app. If you find the framework useful, please consider supporting its development.
|
|
115
|
+
|
|
116
|
+
**[Support Aura on Stripe (Choose what you pay)](https://donate.stripe.com/9B66oH2hHbci9ZNd5jc7u00)**
|
|
117
|
+
*All donations go directly towards maintaining the infrastructure and developing new features like v1.4 Distributed Training.*
|
|
118
|
+
|
|
119
|
+
## 📜 License
|
|
120
|
+
MIT
|
data/Rakefile
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
begin
|
|
4
|
+
require "bundler/gem_tasks" # build / install / release from the gemspec
|
|
5
|
+
rescue LoadError
|
|
6
|
+
# Bundler not available; build/release tasks are skipped but `rake test` works.
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
require "rake/testtask"
|
|
10
|
+
|
|
11
|
+
Rake::TestTask.new(:test) do |t|
|
|
12
|
+
t.libs << "lib"
|
|
13
|
+
t.pattern = "tests/test_*.rb"
|
|
14
|
+
t.verbose = true
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
task default: :test
|
|
18
|
+
|
|
19
|
+
# --- Release helpers ---------------------------------------------------------
|
|
20
|
+
# One-command version bumps. `rake bump:patch` rewrites lib/aura/version.rb and
|
|
21
|
+
# stamps a fresh CHANGELOG heading. Then commit, tag vX.Y.Z, and push the tag --
|
|
22
|
+
# the GitHub Action (.github/workflows/ruby-gem-push.yml) publishes the gem.
|
|
23
|
+
VERSION_FILE = File.expand_path("lib/aura/version.rb", __dir__)
|
|
24
|
+
CHANGELOG_FILE = File.expand_path("CHANGELOG.md", __dir__)
|
|
25
|
+
|
|
26
|
+
def aura_bump(part)
|
|
27
|
+
current = File.read(VERSION_FILE)[/VERSION\s*=\s*"([^"]+)"/, 1]
|
|
28
|
+
major, minor, patch = current.split(".").map(&:to_i)
|
|
29
|
+
case part
|
|
30
|
+
when :major then major, minor, patch = major + 1, 0, 0
|
|
31
|
+
when :minor then minor, patch = minor + 1, 0
|
|
32
|
+
when :patch then patch += 1
|
|
33
|
+
end
|
|
34
|
+
nextv = "#{major}.#{minor}.#{patch}"
|
|
35
|
+
File.write(VERSION_FILE, File.read(VERSION_FILE).sub(/VERSION\s*=\s*"[^"]+"/, %(VERSION = "#{nextv}")))
|
|
36
|
+
aura_stamp_changelog(nextv)
|
|
37
|
+
puts "Bumped #{current} -> #{nextv}"
|
|
38
|
+
puts %(Next: git commit -am "Release v#{nextv}" && git tag v#{nextv} && git push origin HEAD --tags)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def aura_stamp_changelog(version)
|
|
42
|
+
return unless File.exist?(CHANGELOG_FILE)
|
|
43
|
+
|
|
44
|
+
body = File.read(CHANGELOG_FILE)
|
|
45
|
+
return if body.include?("## [#{version}]")
|
|
46
|
+
|
|
47
|
+
entry = "## [#{version}] - #{Time.now.strftime('%Y-%m-%d')}\n\n- _Describe changes here._\n\n"
|
|
48
|
+
updated = body =~ /^## \[/ ? body.sub(/^## \[/, entry + "## [") : "#{body}\n#{entry}"
|
|
49
|
+
File.write(CHANGELOG_FILE, updated)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
namespace :bump do
|
|
53
|
+
desc "Bump patch version (x.y.Z)"
|
|
54
|
+
task(:patch) { aura_bump(:patch) }
|
|
55
|
+
desc "Bump minor version (x.Y.0)"
|
|
56
|
+
task(:minor) { aura_bump(:minor) }
|
|
57
|
+
desc "Bump major version (X.0.0)"
|
|
58
|
+
task(:major) { aura_bump(:major) }
|
|
59
|
+
end
|
data/aura-lang.gemspec
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
require_relative "lib/aura/version"
|
|
2
|
+
|
|
3
|
+
Gem::Specification.new do |s|
|
|
4
|
+
s.name = "aura-lang"
|
|
5
|
+
s.version = Aura::VERSION
|
|
6
|
+
s.summary = "Aura: The Declarative AI Web Framework. A RootSpace.app product founded and developed by John V. Teixido."
|
|
7
|
+
s.description = "A professional-grade framework for building AI pipelines and AI-integrated web apps with Ruby and Torch. A RootSpace.app product founded and developed by John V. Teixido."
|
|
8
|
+
s.authors = ["John V. Teixido"]
|
|
9
|
+
s.email = "john@rootspace.app"
|
|
10
|
+
s.files = Dir["{bin,lib,examples}/**/*", "README.md", "CHANGELOG.md", "LICENSE", "Rakefile", "aura-lang.gemspec"]
|
|
11
|
+
s.homepage = "https://rootspace.app"
|
|
12
|
+
s.license = "MIT"
|
|
13
|
+
s.required_ruby_version = ">= 3.2"
|
|
14
|
+
s.executables << "aura"
|
|
15
|
+
|
|
16
|
+
# Core dependencies needed to parse, transpile, and serve Aura apps.
|
|
17
|
+
s.add_dependency "parslet", "~> 2.0"
|
|
18
|
+
s.add_dependency "sinatra", "~> 4.2"
|
|
19
|
+
s.add_dependency "puma", ">= 7.2", "< 9.0"
|
|
20
|
+
s.add_dependency "json", "~> 2.7"
|
|
21
|
+
s.add_dependency "red-datasets", "~> 0.1"
|
|
22
|
+
s.add_dependency "dotenv", "~> 3.1"
|
|
23
|
+
|
|
24
|
+
# NOTE: `torch-rb` (and the LibTorch native library it binds to) is required
|
|
25
|
+
# only to *train and run* generated models, not to parse/transpile/build.
|
|
26
|
+
# It is intentionally an optional runtime dependency so the gem installs in
|
|
27
|
+
# environments without LibTorch. Install it explicitly to run models:
|
|
28
|
+
# gem install torch-rb
|
|
29
|
+
end
|
data/bin/aura
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# Make the gem's own lib reachable when run straight from a checkout
|
|
5
|
+
# (e.g. `ruby bin/aura ...`), not just when installed as a gem.
|
|
6
|
+
lib = File.expand_path("../lib", __dir__)
|
|
7
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
8
|
+
|
|
9
|
+
require "aura"
|
|
10
|
+
require "fileutils"
|
|
11
|
+
|
|
12
|
+
# The starter app written by `init` / `run` lives in the library
|
|
13
|
+
# (Aura::STARTER_TEMPLATE) so it can't drift from the grammar.
|
|
14
|
+
STARTER_TEMPLATE = Aura::STARTER_TEMPLATE
|
|
15
|
+
|
|
16
|
+
def show_welcome
|
|
17
|
+
puts <<~WELCOME
|
|
18
|
+
Aura Framework v#{Aura::VERSION}
|
|
19
|
+
A RootSpace.app Product | Developed by John V. Teixido
|
|
20
|
+
|
|
21
|
+
Build, Train, and Deploy AI Apps.
|
|
22
|
+
|
|
23
|
+
Usage: aura [command]
|
|
24
|
+
aura run <file.aura> - Serve your Aura app (loads weights, no training)
|
|
25
|
+
aura train <file.aura> - Train the models, persist weights, then exit
|
|
26
|
+
aura check <file.aura> - Transpile and preview generated Ruby
|
|
27
|
+
aura build <file.aura> - Export to a standalone Sinatra app
|
|
28
|
+
aura deploy <file.aura> - Generate deployment assets (--target vercel for LLM apps)
|
|
29
|
+
aura init <name> - Scaffold a new project
|
|
30
|
+
aura console - Open an interactive console (Pry)
|
|
31
|
+
aura --help - Show this help
|
|
32
|
+
WELCOME
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Run a block, turning Aura compile errors into friendly CLI output.
|
|
36
|
+
def guard
|
|
37
|
+
yield
|
|
38
|
+
rescue Aura::ParseError, Aura::SemanticError, Aura::DeployError => e
|
|
39
|
+
warn "Error: #{e.message}"
|
|
40
|
+
exit 1
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Resolve the deploy target from trailing args: `--target vercel`,
|
|
44
|
+
# `--target=vercel`, or `--vercel`. Defaults to "docker".
|
|
45
|
+
def deploy_target(args)
|
|
46
|
+
args = Array(args)
|
|
47
|
+
if (i = args.index("--target")) && args[i + 1]
|
|
48
|
+
args[i + 1]
|
|
49
|
+
elsif (flag = args.find { |a| a.start_with?("--target=") })
|
|
50
|
+
flag.split("=", 2).last
|
|
51
|
+
elsif args.include?("--vercel")
|
|
52
|
+
"vercel"
|
|
53
|
+
else
|
|
54
|
+
"docker"
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
command = ARGV[0]
|
|
59
|
+
filename = ARGV[1]
|
|
60
|
+
|
|
61
|
+
if command.nil?
|
|
62
|
+
show_welcome
|
|
63
|
+
exit 0
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
case command
|
|
67
|
+
when "run"
|
|
68
|
+
if filename && File.exist?(filename)
|
|
69
|
+
guard { Aura.run_file(filename) }
|
|
70
|
+
else
|
|
71
|
+
name = filename || "app.aura"
|
|
72
|
+
puts "File not found: #{name}. Generating a template..."
|
|
73
|
+
File.write(name, STARTER_TEMPLATE)
|
|
74
|
+
puts "Created #{name}. Edit it, then run: aura run #{name}"
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
when "train"
|
|
78
|
+
if filename && File.exist?(filename)
|
|
79
|
+
ENV["AURA_TRAIN"] = "1" # generated code trains (and saves weights) then exits
|
|
80
|
+
guard { Aura.run_file(filename) }
|
|
81
|
+
else
|
|
82
|
+
warn "File not found: #{filename}."
|
|
83
|
+
exit 1
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
when "check"
|
|
87
|
+
if filename && File.exist?(filename)
|
|
88
|
+
guard do
|
|
89
|
+
code = Aura.transpile(File.read(filename))
|
|
90
|
+
puts "Transpilation successful"
|
|
91
|
+
puts code
|
|
92
|
+
end
|
|
93
|
+
else
|
|
94
|
+
warn "File not found: #{filename}."
|
|
95
|
+
exit 1
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
when "build"
|
|
99
|
+
if filename && File.exist?(filename)
|
|
100
|
+
guard do
|
|
101
|
+
out_file = filename.sub(/\.aura\z/, ".rb")
|
|
102
|
+
File.write(out_file, Aura.transpile(File.read(filename)))
|
|
103
|
+
puts "Built standalone application: #{out_file}"
|
|
104
|
+
end
|
|
105
|
+
else
|
|
106
|
+
warn "File not found: #{filename}."
|
|
107
|
+
exit 1
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
when "deploy"
|
|
111
|
+
if filename && File.exist?(filename)
|
|
112
|
+
guard do
|
|
113
|
+
case deploy_target(ARGV[2..])
|
|
114
|
+
when "vercel" then Aura.build_vercel(filename)
|
|
115
|
+
else Aura.build_docker(filename)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
else
|
|
119
|
+
warn "File not found: #{filename}."
|
|
120
|
+
exit 1
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
when "init"
|
|
124
|
+
project_name = filename
|
|
125
|
+
if project_name.nil?
|
|
126
|
+
warn "Please provide a project name."
|
|
127
|
+
exit 1
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
FileUtils.mkdir_p(File.join(project_name, "models"))
|
|
131
|
+
FileUtils.mkdir_p(File.join(project_name, "data"))
|
|
132
|
+
File.write(File.join(project_name, "app.aura"), STARTER_TEMPLATE)
|
|
133
|
+
puts "Created Aura project: #{project_name}"
|
|
134
|
+
puts " Next: cd #{project_name} && aura run app.aura"
|
|
135
|
+
|
|
136
|
+
when "console"
|
|
137
|
+
begin
|
|
138
|
+
require "pry"
|
|
139
|
+
Pry.start
|
|
140
|
+
rescue LoadError
|
|
141
|
+
warn "Pry is not installed. Add it with: gem install pry"
|
|
142
|
+
exit 1
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
when "--help", "-h", "help"
|
|
146
|
+
show_welcome
|
|
147
|
+
|
|
148
|
+
else
|
|
149
|
+
warn "Unknown command: #{command}."
|
|
150
|
+
exit 1
|
|
151
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# LLM assistant with a system prompt and sampling controls.
|
|
2
|
+
model assistant from openai "gpt-4o" do
|
|
3
|
+
system "You are a concise, helpful assistant."
|
|
4
|
+
temperature 0.3
|
|
5
|
+
max_tokens 512
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
route "/chat" post do
|
|
9
|
+
output prediction from assistant.predict(message) format :json
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
run web on port: 3000
|
data/examples/hello.aura
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
dataset "mnist" from huggingface "mnist"
|
|
2
|
+
|
|
3
|
+
environment production do
|
|
4
|
+
log_level :info
|
|
5
|
+
device :cuda
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
model classifier neural_network do
|
|
9
|
+
# Input 28x28 grayscale image
|
|
10
|
+
input shape(28, 28, 1)
|
|
11
|
+
|
|
12
|
+
layer conv2d filters: 32, kernel: 3
|
|
13
|
+
layer maxpool2d size: 2
|
|
14
|
+
layer batchnorm
|
|
15
|
+
layer flatten
|
|
16
|
+
|
|
17
|
+
layer dense units: 128, activation: :relu
|
|
18
|
+
layer dropout rate: 0.2
|
|
19
|
+
output units: 10, activation: :softmax
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
train classifier on "mnist" do
|
|
23
|
+
epochs 10
|
|
24
|
+
batch_size 64
|
|
25
|
+
optimizer :adam, learning_rate: 0.0005
|
|
26
|
+
loss :cross_entropy
|
|
27
|
+
metrics :accuracy
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
evaluate classifier on "mnist/test"
|
|
31
|
+
|
|
32
|
+
route "/v1/predict" post do
|
|
33
|
+
output prediction from classifier.predict(image) format :json
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
run web on port: 3000
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Sentiment classifier: embedding -> LSTM -> 2-class output.
|
|
2
|
+
model sentiment neural_network do
|
|
3
|
+
layer embedding vocab: 20000, dim: 128
|
|
4
|
+
layer lstm units: 256
|
|
5
|
+
layer dropout rate: 0.3
|
|
6
|
+
output units: 2, activation: :softmax
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
route "/sentiment" post do
|
|
10
|
+
output prediction from sentiment.predict(tokens) as :label format :json
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
run web on port: 3000
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Transfer-learning image API (mirrors the README example).
|
|
2
|
+
# Scaffolding a production vision API
|
|
3
|
+
environment production do
|
|
4
|
+
device :cuda
|
|
5
|
+
log_level :info
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
model vision transfer from :resnet18 do
|
|
9
|
+
# Fine-tune the head while keeping features frozen
|
|
10
|
+
freeze until :layer_4
|
|
11
|
+
output units: 10, activation: :softmax
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
train vision on "imagenet-subset" do
|
|
15
|
+
epochs 20
|
|
16
|
+
optimizer :adam, learning_rate: 0.0001
|
|
17
|
+
scheduler :step_lr # Advanced LR scheduling
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
route "/v1/classify" post do
|
|
21
|
+
authenticate with :token
|
|
22
|
+
output prediction from vision.predict(image)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
run web on port: 8080
|