Skip to content

Commit b0571ef

Browse files
Use Svelte source for Gradio components directly in Trackio dashboard (#450)
Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>
1 parent 80d7345 commit b0571ef

74 files changed

Lines changed: 10509 additions & 4962 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.changeset/busy-nails-relate.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"trackio": minor
3+
---
4+
5+
feat:Use Svelte source for Gradio components directly in Trackio dashboard

.github/workflows/format.yml

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,19 @@ jobs:
2929
3030
- name: Check code with ruff
3131
run: |
32-
ruff check .
32+
ruff check .
33+
34+
- name: Set up Node.js
35+
uses: actions/setup-node@v4
36+
with:
37+
node-version: '20'
38+
39+
- name: Install frontend dependencies
40+
run: |
41+
cd trackio/frontend
42+
npm ci
43+
44+
- name: Lint frontend
45+
run: |
46+
cd trackio/frontend
47+
npm run lint

.github/workflows/test.yml

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,15 @@ jobs:
1212
matrix:
1313
os: [ubuntu-latest, windows-latest]
1414
runs-on: ${{ matrix.os }}
15+
defaults:
16+
run:
17+
shell: bash
1518

1619
steps:
1720
- uses: actions/checkout@v3
1821

1922
- name: Set up Python
23+
id: setup-python
2024
uses: actions/setup-python@v4
2125
with:
2226
python-version: '3.10'
@@ -48,20 +52,34 @@ jobs:
4852
4953
- name: Install Python dependencies
5054
run: |
51-
uv pip install --system -e .[dev,tensorboard,spaces] --prerelease=allow
52-
uv pip install --system pytest --prerelease=allow
55+
uv pip install --system -e '.[dev,tensorboard,spaces]' --prerelease=allow --python "${{ steps.setup-python.outputs.python-path }}"
56+
uv pip install --system pytest --prerelease=allow --python "${{ steps.setup-python.outputs.python-path }}"
57+
58+
- name: Set up Node.js
59+
if: matrix.os == 'ubuntu-latest'
60+
uses: actions/setup-node@v4
61+
with:
62+
node-version: '20'
63+
64+
- name: Build frontend
65+
if: matrix.os == 'ubuntu-latest'
66+
run: |
67+
cd trackio/frontend
68+
npm ci
69+
npm run build
5370
5471
- name: Install Playwright
72+
if: matrix.os == 'ubuntu-latest'
5573
run: |
56-
playwright install
57-
74+
"${{ steps.setup-python.outputs.python-path }}" -m playwright install chromium
75+
5876
- name: Run backend unit tests
5977
run: |
60-
pytest --deselect=tests/ui --deselect=tests/e2e-spaces
78+
"${{ steps.setup-python.outputs.python-path }}" -m pytest --deselect=tests/ui --deselect=tests/e2e-spaces
6179
6280
- name: Run ui/ux interaction tests
6381
if: matrix.os == 'ubuntu-latest'
6482
run: |
65-
pytest tests/ui
83+
"${{ steps.setup-python.outputs.python-path }}" -m pytest tests/ui
6684
6785

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,5 @@ trackio.db
1111
node_modules/
1212
dist/
1313
build/
14-
tf_test_run/
14+
tf_test_run/
15+
test.py

CLAUDE.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,9 @@ Trackio is a lightweight experiment tracking library that provides a drop-in rep
4848
### Core Flow
4949
1. **User API** (`trackio/__init__.py`, `run.py`) - Provides wandb-compatible API (`init()`, `log()`, `finish()`)
5050
2. **Storage Layer** (`sqlite_storage.py`) - Manages SQLite database operations for local persistence
51-
3. **UI Layer** (`ui/`) - Gradio-based web dashboard for visualization
52-
4. **Background Sync** (`commit_scheduler.py`) - Optional Hugging Face dataset synchronization
51+
3. **API Layer** (`ui/main.py`) - Gradio-based API server exposing endpoints via `gr.api()`
52+
4. **Frontend** (`frontend/`) - Svelte 5 SPA dashboard served alongside the Gradio API
53+
5. **Background Sync** (`commit_scheduler.py`) - Optional Hugging Face dataset synchronization
5354

5455
### Key Design Decisions
5556

@@ -68,7 +69,8 @@ Tests are split into unit tests (testing individual modules) and e2e tests (test
6869
### Important Files for Common Tasks
6970

7071
- **Adding new logging features**: Modify `run.py` (Run class) and `sqlite_storage.py` (storage operations)
71-
- **Changing UI/dashboard**: Edit `ui/` (Gradio interface)
72+
- **Changing UI/dashboard**: Edit `frontend/src/` (Svelte 5 components), then run `npm run build` in `trackio/frontend/`
73+
- **Changing API endpoints**: Edit `ui/main.py` (Gradio API layer)
7274
- **Modifying API compatibility**: Update `trackio/__init__.py` and ensure wandb compatibility
7375
- **Adding import formats**: Extend `imports.py` with new import functions
7476
- **CLI modifications**: Update `cli.py` and entry points in `pyproject.toml`

README.md

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@
2020

2121
</div>
2222

23-
Welcome to `trackio`: a lightweight, <u>free</u> experiment tracking Python library built by Hugging Face 🤗. It is local-first, supports very high logging throughputs for many parallel experiments, and provides an easy CLI interface for querying, perfect for LLM-driven experimenting.
23+
Welcome to `trackio`: a lightweight, <u>free</u> experiment tracking library built by Hugging Face 🤗. The **logging API, storage, and server** are implemented in **Python**; the **dashboard** is a **Svelte 5** single-page app served alongside a **Gradio** API server, with several UI controls built from **Gradio’s component source** (sliders, checkboxes, etc.) for consistency with the Gradio ecosystem. Trackio is local-first, supports very high logging throughputs for many parallel experiments, and provides an easy CLI interface for querying, perfect for LLM-driven experimenting.
2424

25-
For human users, Trackio also ships with a Gradio-based dashboard you can use to view metrics, media, tables, alerts, etc:
25+
For human users, Trackio ships with that dashboard so you can view metrics, media, tables, alerts, etc.:
2626

2727
![Screen Recording 2025-11-06 at 5 34 50 PM](https://github.com/user-attachments/assets/8c9c1b96-f17a-401c-83a4-26ac754f89c7)
2828

@@ -37,12 +37,12 @@ Trackio's main features:
3737

3838
- **Local-first** design: dashboard runs locally by default. You can also host it on Spaces by specifying a `space_id` in `trackio.init()`.
3939
- Persists logs in a Sqlite database locally (or, if you provide a `space_id`, in a private Hugging Face Dataset)
40-
- Visualize experiments with a Gradio dashboard locally (or, if you provide a `space_id`, on Hugging Face Spaces)
40+
- Visualize experiments with a **Svelte 5** dashboard locally (or, if you provide a `space_id`, on Hugging Face Spaces)
4141
- **LLM-friendly**: Built with autonomous ML experiments in mind, Trackio includes a CLI for programmatic access and a Python API for run management, making it easy for LLMs to log metrics and query experiment data.
4242

4343
- **Free**: Everything here, including hosting on Hugging Face, is free!
4444

45-
Trackio is designed to be lightweight and _forkable_. It is written almost entirely in Python so that developers can easily fork the repository and add functionality that they care about.
45+
Trackio is designed to be lightweight and _forkable_: **Python** for the backend and API, **Svelte 5** for the dashboard, and **Gradio component** code where UI widgets need to match Gradio behavior—so developers can fork the repository and extend either side.
4646

4747
## Installation
4848

@@ -193,14 +193,15 @@ If you are hosting your Trackio dashboard on Spaces, then you can embed the url
193193

194194
Supported query parameters:
195195

196-
- `project`: (string) Filter the dashboard to show only a specific project
197-
- `metrics`: (comma-separated list) Filter the dashboard to show only specific metrics, e.g. `train_loss,train_accuracy`
198-
- `sidebar`: (string: one of "hidden" or "collapsed"). If "hidden", then the sidebar will not be visible. If "collapsed", the sidebar will be in a collapsed state initially but the user will be able to open it. Otherwise, by default, the sidebar is shown in an open and visible state.
199-
- `footer`: (string: "false"). When set to "false", hides the Gradio footer. By default, the footer is visible.
200-
- `xmin`: (number) Set the initial minimum value for the x-axis limits across all metric plots.
201-
- `xmax`: (number) Set the initial maximum value for the x-axis limits across all metric plots.
196+
- `project`: (string) Open the dashboard on this project only. The project picker is hidden and the selection cannot be changed while this parameter is present (useful for embeds). The alias `selected_project` is accepted for the same behavior.
197+
- `metrics`: (comma-separated list) Show only metrics whose names match exactly (after splitting on commas), e.g. `train_loss,train_accuracy`. Applied as the metrics filter on the Metrics page.
198+
- `sidebar`: (string) One of `hidden`, `collapsed`, or omitted (default). **`hidden`** removes the sidebar entirely (full-width content; no rail). **`collapsed`** starts with the sidebar collapsed to the narrow rail; the user can expand it. By default the sidebar is open.
199+
- `footer`: (string: "false"). When set to "false", hides the Gradio footer (Gradio-hosted Spaces). By default, the footer is visible.
200+
- `xmin` / `xmax`: (numbers, use both together) Set the initial horizontal zoom range on the Metrics plots (shared x-axis window). Both must be valid numbers with `xmin < xmax`.
202201
- `smoothing`: (number) Set the initial value of the smoothing slider (0-20, where 0 = no smoothing).
203202
- `accordion`: (string: "hidden"). When set to "hidden", hides the section header accordions around metric groups. By default, section headers are visible.
203+
- `theme`: (string) Dashboard theme, e.g. `light` or `dark` (see theme behavior in the app).
204+
- `write_token`: (string) One-time token written to a cookie for write access on Hugging Face Spaces deployments; stripped from the URL after load.
204205

205206
## Alerts
206207

@@ -294,9 +295,9 @@ pip install -e ".[dev,tensorboard]"
294295

295296
## Forking Trackio
296297

297-
Trackio is designed to be extremely forkable. It is written entirely in Python with a Gradio-based dashboard, so you can fork the repo, make changes to the source code (e.g. adding new elements to the dashboard, custom metrics, or new pages), and see those changes reflected immediately when running locally.
298+
Trackio is designed to be extremely forkable. The codebase is **not** Python-only: the **backend** lives in Python (SQLite, Gradio API, CLI), and the **dashboard** is **Svelte 5** under `trackio/frontend/` (with a production build bundled into the Python package). UI controls that mirror Gradio are implemented using **Gradio’s component source** as a starting point. You can fork the repo, change Python, frontend, or both (e.g. new dashboard pages, metrics, API routes), and see updates when running locally after installing in editable mode and rebuilding the frontend where needed.
298299

299-
Even better, if you deploy your Trackio dashboard to Hugging Face Spaces (by setting a `space_id` in `trackio.init()`), the Space UI will reflect your local version of Trackio — so any customizations you make to the Python source carry over to your hosted dashboard as well.
300+
If you deploy your Trackio dashboard to Hugging Face Spaces (by setting a `space_id` in `trackio.init()`), the Space UI reflects **your** checkout of Trackio—including any changes to the Python backend and the built Svelte assets.
300301

301302
To get started, follow the [Contributing Guide](#CONTRIBUTING.md) instructions to set up Trackio locally, then make your changes and run `trackio show` to preview them locally.
302303

hatch_build.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import os
2+
import shutil
3+
import subprocess
4+
import sys
5+
from pathlib import Path
6+
7+
from hatchling.builders.hooks.plugin.interface import BuildHookInterface
8+
9+
10+
def _run_npm(args: list[str], cwd: str) -> None:
11+
if sys.platform == "win32":
12+
subprocess.run(["cmd", "/c", "npm", *args], cwd=cwd, check=True)
13+
else:
14+
subprocess.run(["npm", *args], cwd=cwd, check=True)
15+
16+
17+
class CustomBuildHook(BuildHookInterface):
18+
PLUGIN_NAME = "custom"
19+
20+
def initialize(self, version: str, build_data: dict) -> None:
21+
if os.environ.get("SKIP_FRONTEND_BUILD") == "1":
22+
return
23+
24+
root = Path(self.root)
25+
frontend = root / "trackio" / "frontend"
26+
dist_index = frontend / "dist" / "index.html"
27+
if (
28+
dist_index.is_file()
29+
and os.environ.get("TRACKIO_FRONTEND_FORCE_REBUILD") != "1"
30+
):
31+
return
32+
33+
if not (frontend / "package.json").is_file():
34+
return
35+
36+
if not shutil.which("npm"):
37+
raise RuntimeError(
38+
"The Trackio dashboard frontend is not built (trackio/frontend/dist/index.html "
39+
"is missing) and npm is not available. Install Node.js and npm, then run "
40+
"`cd trackio/frontend && npm ci && npm run build`, or set SKIP_FRONTEND_BUILD=1 "
41+
"only if dist/ was produced another way."
42+
)
43+
44+
_run_npm(["ci"], str(frontend))
45+
_run_npm(["run", "build"], str(frontend))

pyproject.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ requires-python = ">=3.10"
1515
dependencies = [
1616
"pandas<3.0.0",
1717
"huggingface-hub<2.0.0",
18-
"gradio[oauth]>=6.8.0,<7.0.0",
18+
"gradio[oauth]>=6.10.0,<7.0.0",
1919
"numpy<3.0.0",
2020
"pillow<12.0.0",
2121
"orjson>=3.0,<4.0.0",
@@ -59,8 +59,11 @@ spaces = [
5959
[project.scripts]
6060
trackio = "trackio.cli:main"
6161

62+
[tool.hatch.build.hooks.custom]
63+
6264
[tool.hatch.build.targets.wheel]
6365
packages = ["trackio"]
66+
artifacts = ["trackio/frontend/dist/**"]
6467

6568
[tool.hatch.version]
6669
path = "trackio/package.json"
@@ -76,6 +79,7 @@ exclude = [
7679
"__pycache__",
7780
"build",
7881
"dist",
82+
"trackio/frontend",
7983
]
8084

8185
# Same as Black.

tests/e2e-spaces/test_cli_remote.py

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import json
22
import secrets
33
import subprocess
4+
import time
45

56

67
def test_cli_remote_list_and_get(test_space_id):
@@ -14,14 +15,18 @@ def test_cli_remote_list_and_get(test_space_id):
1415
trackio.log({"loss": 0.3, "acc": 0.9})
1516
trackio.finish()
1617

17-
def cli(*args):
18-
result = subprocess.run(
19-
["trackio", *args, "--space", test_space_id, "--json"],
20-
capture_output=True,
21-
text=True,
22-
)
23-
assert result.returncode == 0, f"CLI failed: {result.stderr}"
24-
return json.loads(result.stdout)
18+
def cli(*args, retries=3):
19+
for attempt in range(retries):
20+
result = subprocess.run(
21+
["trackio", *args, "--space", test_space_id, "--json"],
22+
capture_output=True,
23+
text=True,
24+
)
25+
if result.returncode == 0:
26+
return json.loads(result.stdout)
27+
if attempt < retries - 1:
28+
time.sleep(10)
29+
assert False, f"CLI failed after {retries} attempts: {result.stderr}"
2530

2631
projects = cli("list", "projects")
2732
assert project_name in projects["projects"]

tests/e2e-spaces/test_data_robustness.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,15 @@ def wrapped_predict(*args, **kwargs):
148148
time.sleep(10)
149149
trackio.finish()
150150

151-
verify_client = Client(test_space_id)
151+
verify_client = None
152+
deadline = time.time() + 60
153+
while time.time() < deadline:
154+
try:
155+
verify_client = Client(test_space_id, verbose=False)
156+
break
157+
except Exception:
158+
time.sleep(10)
159+
assert verify_client is not None, "Could not connect to Space"
152160
summary = verify_client.predict(
153161
project=project_name, run=run_name, api_name="/get_run_summary"
154162
)

0 commit comments

Comments
 (0)