Skip to content

Commit c9a8188

Browse files
author
Atome LM Team
committed
v2: real 'superesp' console command (editable + wheel), install-safe export path, version 2.0.0, consistent CLI messages
1 parent 8d2bc26 commit c9a8188

3 files changed

Lines changed: 52 additions & 23 deletions

File tree

pyproject.toml

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "atome-llm"
7-
version = "0.3.0"
7+
version = "2.0.0"
88
description = "Atome LM — a tiny ternary language model designed for microcontroller deployment via the Atome C99 inference engine."
99
readme = "README.md"
1010
requires-python = ">=3.10"
@@ -29,11 +29,19 @@ dependencies = [
2929
Homepage = "https://atomelm.com"
3030
Demo = "https://atomelm.com/demo.html"
3131

32+
[project.scripts]
33+
superesp = "superesp.cli:main"
34+
3235
[project.optional-dependencies]
3336
dev = ["pytest>=7", "cryptography>=41", "scipy>=1.10"]
3437
# SuperESP (v2) runtime extras: Ed25519 attestation + audio/voice feature extraction
3538
# (+ pyserial for on-device log capture). Install with: pip install -e ".[superesp]"
3639
superesp = ["cryptography>=41", "scipy>=1.10", "pyserial>=3.5", "esptool>=4.7"]
3740

3841
[tool.setuptools.packages.find]
39-
include = ["atome_llm*"]
42+
include = ["atome_llm*", "superesp*"]
43+
44+
# Ship the read-only data a fresh install needs (signed head blobs, zoo registry,
45+
# prebuilt firmware). Training/firmware-build still expect a source checkout.
46+
[tool.setuptools.package-data]
47+
"superesp" = ["artifacts/*", "artifacts/reports/*", "esp32/prebuilt/**", "zoo/*.json", "zoo/*.html"]

superesp/cli.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
"""superesp.cli — one-command reproduction of SuperESP applications.
22
3-
python3 -m superesp.cli list
4-
python3 -m superesp.cli train <head> # a built-in head
5-
python3 -m superesp.cli train --csv my.csv --label-col state --name mysensor
6-
python3 -m superesp.cli flashplan <name> # how to bake the blob into firmware
3+
After `pip install -e .` the `superesp` command is available (or use
4+
`python3 -m superesp.cli` without installing):
5+
6+
superesp list
7+
superesp train <head> # a built-in head
8+
superesp train --csv my.csv --label-col state --name mysensor
9+
superesp flashplan <name> # how to bake the blob into firmware
710
811
`train` does the whole pipeline: split (leak-free) -> train tiny ternary head ->
912
held-out eval + abstention + novelty -> export ATOMECL01 -> Ed25519 attestation,
@@ -33,7 +36,7 @@ def _load(args):
3336
return load_csv(args.csv, label_col=args.label_col, name=args.name)
3437
from superesp.heads import BY_NAME
3538
if args.head not in BY_NAME:
36-
raise SystemExit(f"unknown head {args.head!r}; see `cli list`")
39+
raise SystemExit(f"unknown head {args.head!r}; see `superesp list`")
3740
return BY_NAME[args.head].loader(seed=0)
3841

3942

@@ -42,7 +45,7 @@ def cmd_list(_):
4245
print("Built-in SuperESP heads:")
4346
for h in HEADS:
4447
print(f" {h.name:11s}{h.blurb}")
45-
print("\nOr bring your own: cli train --csv data.csv --label-col <col> --name <name>")
48+
print("\nOr bring your own: superesp train --csv data.csv --label-col <col> --name <name>")
4649

4750

4851
def cmd_train(args):
@@ -67,7 +70,7 @@ def cmd_train(args):
6770
sign.save_attestation(att, ART / f"{name}.att.json")
6871
ok, _ = sign.verify(blob, att)
6972
print(f" exported {st['total_bytes']} B -> {blob.name}; attestation verify={'OK' if ok else 'FAIL'}")
70-
print(f" next: python3 -m superesp.cli flashplan {name}")
73+
print(f" next: superesp flashplan {name}")
7174

7275

7376
def cmd_targets(_):

superesp/framework/export.py

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,38 @@
1616
import sys
1717
from pathlib import Path
1818

19-
_REPO = Path(__file__).resolve().parents[2]
20-
sys.path.insert(0, str(_REPO))
21-
22-
# Load scripts/export_to_atome.py as a module to reuse its writers.
23-
_spec = importlib.util.spec_from_file_location(
24-
"_atome_export", _REPO / "scripts" / "export_to_atome.py"
25-
)
26-
_exp = importlib.util.module_from_spec(_spec)
27-
_spec.loader.exec_module(_exp)
28-
29-
write_ternary = _exp.write_ternary
30-
write_conv = _exp.write_conv
31-
write_norm = _exp.write_norm
32-
write_ssm = _exp.write_ssm
19+
def _find_export_script() -> Path | None:
20+
"""Locate scripts/export_to_atome.py by walking up from this file.
21+
22+
Works from a source checkout or an editable install (files stay in place).
23+
A non-editable wheel install has no scripts/ dir; in that case exporting a
24+
new blob needs a source checkout, so we defer a clear error to call time
25+
rather than crashing at import (read-only commands stay usable).
26+
"""
27+
for base in Path(__file__).resolve().parents:
28+
cand = base / "scripts" / "export_to_atome.py"
29+
if cand.exists():
30+
sys.path.insert(0, str(base))
31+
return cand
32+
return None
33+
34+
_SCRIPT = _find_export_script()
35+
if _SCRIPT is not None:
36+
_spec = importlib.util.spec_from_file_location("_atome_export", _SCRIPT)
37+
_exp = importlib.util.module_from_spec(_spec)
38+
_spec.loader.exec_module(_exp)
39+
write_ternary = _exp.write_ternary
40+
write_conv = _exp.write_conv
41+
write_norm = _exp.write_norm
42+
write_ssm = _exp.write_ssm
43+
else:
44+
def _need_checkout(*_a, **_k):
45+
raise RuntimeError(
46+
"Exporting a blob needs the Atome source tree (scripts/export_to_atome.py).\n"
47+
"Install from a checkout: git clone …/atome-lm && pip install -e .\n"
48+
"(A plain wheel install can run read-only commands but not train/export.)"
49+
)
50+
write_ternary = write_conv = write_norm = write_ssm = _need_checkout
3351

3452
MAGIC = b"ATOMECL01"
3553

0 commit comments

Comments
 (0)