Skip to content

Commit 7d52dfd

Browse files
Fix .sync() and add .freeze() as a separate methods (#477)
Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>
1 parent fcb476c commit 7d52dfd

20 files changed

Lines changed: 689 additions & 156 deletions

.changeset/five-points-thank.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:Fix `.sync()` and add `.freeze()` as a separate methods

docs/source/api.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@
3232

3333
[[autodoc]] sync
3434

35+
## freeze
36+
37+
[[autodoc]] freeze
38+
3539
## delete_project
3640

3741
[[autodoc]] delete_project

docs/source/cli_commands.md

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,59 @@ For private Spaces, pass `--hf-token` or ensure you are logged in via `huggingfa
2323
trackio list projects --space username/private-space --hf-token hf_xxxxx
2424
```
2525

26-
> **Note:** The `show`, `status`, `sync`, and `skills` commands are local-only and do not support `--space`.
26+
> **Note:** The `show`, `status`, `sync`, `freeze`, and `skills` commands are local-only and do not support `--space`.
27+
28+
## Sync Command
29+
30+
Upload a local project to a Hugging Face Space:
31+
32+
```sh
33+
trackio sync --project "my-project" --space-id "username/space_id"
34+
```
35+
36+
Deploy as a static Space (reads from an HF Bucket, no server needed):
37+
38+
```sh
39+
trackio sync --project "my-project" --space-id "username/space_id" --sdk static
40+
```
41+
42+
Sync all projects that have unsynced data to their configured Spaces:
43+
44+
```sh
45+
trackio sync --all
46+
```
47+
48+
| Flag | Description |
49+
|------|-------------|
50+
| `--project` | The name of the project to sync (required unless `--all` is used) |
51+
| `--space-id` | The HF Space ID to sync to (e.g. `username/space_id`). If not provided, uses the previously-configured Space |
52+
| `--all` | Sync all projects with unsynced data |
53+
| `--sdk` | `gradio` (default) for a live server, or `static` for a read-only bucket-backed Space |
54+
| `--private` | Make the Space private if creating a new one |
55+
| `--force` | Overwrite the existing database without prompting |
56+
57+
## Freeze Command
58+
59+
Create a read-only static Space snapshot from a live Gradio Space:
60+
61+
```sh
62+
trackio freeze --space-id "username/my-space" --project "my-project"
63+
```
64+
65+
Specify a custom destination Space:
66+
67+
```sh
68+
trackio freeze --space-id "username/my-space" --project "my-project" --new-space-id "username/my-snapshot"
69+
```
70+
71+
| Flag | Description |
72+
|------|-------------|
73+
| `--space-id` | The source Gradio Space ID (required) |
74+
| `--project` | The project to freeze (required) |
75+
| `--new-space-id` | The destination static Space ID. Defaults to `{space_id}_static` |
76+
| `--private` | Make the new static Space private |
77+
78+
> **Note:** The source must be a Gradio Space with a bucket mounted at `/data`. If the destination Space already exists and is not a Trackio static Space, `freeze` will refuse to overwrite it.
2779
2880
## List Commands
2981

docs/source/deploy_embed.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,61 @@ trackio.init(project="my-project", space_id="username/space_id")
1818

1919
it will use an existing or automatically deploy a new Hugging Face Space as needed. You should be logged in with the `huggingface-cli` locally and your token should have write permissions to create the Space.
2020

21+
## Syncing Local Projects to Spaces
22+
23+
If you've been logging locally and want to upload your data to a Space after the fact, use `sync`:
24+
25+
```py
26+
trackio.sync(project="my-project", space_id="username/space_id")
27+
```
28+
29+
Or from the CLI:
30+
31+
```sh
32+
trackio sync --project "my-project" --space-id "username/space_id"
33+
```
34+
35+
By default, `sync` deploys a **Gradio Space** with a live server. You can also deploy a **static Space** that reads from an HF Bucket (no server needed):
36+
37+
```py
38+
trackio.sync(project="my-project", space_id="username/space_id", sdk="static")
39+
```
40+
41+
```sh
42+
trackio sync --project "my-project" --space-id "username/space_id" --sdk static
43+
```
44+
45+
Static Spaces are lightweight and free — they serve a read-only dashboard backed by Parquet files in an HF Bucket.
46+
47+
## Freezing a Space Snapshot
48+
49+
If you have a live Gradio Space and want to create a read-only static snapshot of a project's data, use `freeze`:
50+
51+
```py
52+
trackio.freeze(space_id="username/my-space", project="my-project")
53+
```
54+
55+
Or from the CLI:
56+
57+
```sh
58+
trackio freeze --space-id "username/my-space" --project "my-project"
59+
```
60+
61+
This creates a new static Space (by default named `{space_id}_static`) containing a snapshot of the project's data from the source Space's bucket. The original Space is not modified.
62+
63+
You can customize the destination:
64+
65+
```py
66+
trackio.freeze(
67+
space_id="username/my-space",
68+
project="my-project",
69+
new_space_id="username/my-snapshot",
70+
private=True,
71+
)
72+
```
73+
74+
> **Note:** `freeze()` requires the source to be a Gradio Space with a bucket mounted at `/data`. If the destination Space already exists and is not a Trackio static Space, `freeze()` will refuse to overwrite it.
75+
2176
## Embedding a Trackio Dashboard
2277

2378
One of the reasons we created `trackio` was to make it easy to embed live dashboards on websites, blog posts, or anywhere else you can embed a website.

docs/source/quickstart.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,4 +128,4 @@ trackio.sync(project="my-project", space_id="username/space_id")
128128
</hfoption>
129129
</hfoptions>
130130

131-
This will create the Space if it does not already exist, and upload all runs and associated data to the Space.
131+
This will create the Space if it does not already exist, and upload all runs and associated data to the Space. You can also sync to a lightweight static Space with `sdk="static"`, or create a read-only snapshot of a live Space with [`freeze`](deploy_embed.md#freezing-a-space-snapshot). See the [Deploy and Embed Dashboards](deploy_embed.md) page for more details.
Lines changed: 20 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,48 @@
11
"""
2-
Example: deploy a Gradio Space during training, then convert it to a static Space once done.
2+
Example: Log locally, sync to a Gradio Space, then freeze a static snapshot.
33
4-
This demonstrates the Gradio -> Static conversion flow:
5-
1. Start training with a live Gradio dashboard (real-time updates)
6-
2. After training finishes, convert the Space to static (no server needed, cheaper)
4+
This demonstrates the full Gradio -> freeze flow:
5+
1. Log training metrics locally
6+
2. Sync the project to a live Gradio Space
7+
3. Freeze the Gradio Space into a read-only static Space (no server needed)
78
89
Usage:
910
python examples/convert-gradio-to-static.py
1011
"""
1112

1213
import math
1314
import random
14-
import time
1515

1616
import trackio
1717

1818
PROJECT = f"gradio-to-static-{random.randint(100000, 999999)}"
19-
SPACE_ID = f"convert-demo-{random.randint(100000, 999999)}"
2019
EPOCHS = 10
2120

2221
for run in range(2):
2322
trackio.init(
2423
project=PROJECT,
24+
space_id=PROJECT,
2525
name=f"run-{run}",
2626
config={"epochs": EPOCHS, "lr": 0.001 * (run + 1), "batch_size": 32},
27-
space_id=SPACE_ID,
28-
auto_log_gpu=False,
2927
)
30-
3128
for epoch in range(EPOCHS):
3229
progress = epoch / EPOCHS
33-
loss = 2.0 * math.exp(-3 * progress) + 0.1 + random.gauss(0, 0.05)
34-
acc = 0.95 / (1 + math.exp(-6 * (progress - 0.5))) + random.gauss(0, 0.02)
35-
30+
loss = max(0.01, 2.0 * math.exp(-3 * progress) + 0.1 + random.gauss(0, 0.05))
31+
acc = min(
32+
0.99,
33+
max(
34+
0, 0.95 / (1 + math.exp(-6 * (progress - 0.5))) + random.gauss(0, 0.02)
35+
),
36+
)
3637
trackio.log(
37-
{
38-
"train/loss": round(max(0.01, loss), 4),
39-
"train/accuracy": round(min(0.99, max(0, acc)), 4),
40-
},
38+
{"train/loss": round(loss, 4), "train/accuracy": round(acc, 4)},
4139
step=epoch,
4240
)
43-
44-
trackio.log_system(
45-
{
46-
"cpu_percent": round(40 + epoch * 3 + random.uniform(-2, 2), 1),
47-
"memory_gb": round(4.0 + epoch * 0.1 + random.uniform(-0.05, 0.05), 2),
48-
}
49-
)
50-
51-
time.sleep(0.3)
52-
5341
trackio.finish()
5442

55-
print("\nTraining complete. Converting Gradio Space to static...")
56-
space_id = trackio.sync(project=PROJECT, space_id=SPACE_ID, sdk="static")
57-
print(f"Static dashboard: https://huggingface.co/spaces/{space_id}")
43+
44+
print("Freezing a static snapshot from the Gradio Space...")
45+
static_space_id = trackio.freeze(
46+
space_id=PROJECT, project=PROJECT, new_space_id=f"{PROJECT}_static"
47+
)
48+
print(f"Static snapshot: https://huggingface.co/spaces/{static_space_id}")

examples/sync-gradio-space.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
"""
2+
Example: Log training data locally, then sync the project to a Gradio Space.
3+
4+
Usage:
5+
python examples/sync-gradio-space.py
6+
7+
This will:
8+
1. Log a few runs of fake training metrics locally (no space_id in init)
9+
2. Call trackio.sync() to upload the local project to a live Gradio Space
10+
11+
Set HF_TOKEN or run `huggingface-cli login` first.
12+
"""
13+
14+
import math
15+
import random
16+
17+
import trackio
18+
19+
PROJECT = f"sync-gradio-demo-{random.randint(100000, 999999)}"
20+
EPOCHS = 15
21+
22+
for run_idx in range(3):
23+
trackio.init(
24+
project=PROJECT,
25+
name=f"run-{run_idx}",
26+
config={"lr": 0.001 * (run_idx + 1), "epochs": EPOCHS},
27+
)
28+
for epoch in range(EPOCHS):
29+
progress = epoch / EPOCHS
30+
loss = max(0.05, 2.5 * math.exp(-3 * progress) + random.gauss(0, 0.1))
31+
acc = min(
32+
0.95, 0.9 / (1 + math.exp(-6 * (progress - 0.5))) + random.gauss(0, 0.03)
33+
)
34+
trackio.log({"train/loss": round(loss, 4), "train/accuracy": round(acc, 4)})
35+
trackio.finish()
36+
37+
print("Training complete. Syncing to a Gradio Space...")
38+
space_id = trackio.sync(project=PROJECT)
39+
print(f"Dashboard: https://huggingface.co/spaces/{space_id}")

examples/sync-static-space.py

Lines changed: 25 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
"""
2-
Example: Log some fake training data, then sync to a static HF Space.
2+
Example: Log training data locally, sync to a static Space, then log more and sync again.
33
44
Usage:
55
python examples/sync-static-space.py
66
77
This will:
8-
1. Log a few runs of fake training metrics locally
9-
2. Call trackio.sync() which uploads the local project to an HF Bucket
10-
and deploys a static dashboard Space (no running server needed)
8+
1. Log an initial run of fake training metrics locally
9+
2. Sync to a static HF Space (uploads to an HF Bucket, no server needed)
10+
3. Log a second run with more data
11+
4. Sync again -- the static Space now contains both runs
1112
1213
Set HF_TOKEN or run `huggingface-cli login` first.
1314
"""
@@ -21,33 +22,29 @@
2122
EPOCHS = 15
2223

2324

24-
def fake_loss(epoch, max_epochs):
25+
def fake_metrics(epoch, max_epochs):
2526
progress = epoch / max_epochs
26-
return max(0.05, 2.5 * math.exp(-3 * progress) + random.gauss(0, 0.2))
27+
loss = max(0.05, 2.5 * math.exp(-3 * progress) + random.gauss(0, 0.1))
28+
acc = min(0.95, 0.9 / (1 + math.exp(-6 * (progress - 0.5))) + random.gauss(0, 0.03))
29+
return round(loss, 4), round(acc, 4)
2730

2831

29-
def fake_accuracy(epoch, max_epochs):
30-
progress = epoch / max_epochs
31-
return min(
32-
0.95, 0.9 / (1 + math.exp(-6 * (progress - 0.5))) + random.gauss(0, 0.05)
33-
)
34-
35-
36-
for run_idx in range(3):
37-
trackio.init(
38-
project=PROJECT,
39-
name=f"run-{run_idx}",
40-
config={"lr": 0.001 * (run_idx + 1), "epochs": EPOCHS},
41-
)
42-
for epoch in range(EPOCHS):
43-
trackio.log(
44-
{
45-
"train/loss": round(fake_loss(epoch, EPOCHS), 4),
46-
"train/accuracy": round(fake_accuracy(epoch, EPOCHS), 4),
47-
"val/loss": round(fake_loss(epoch, EPOCHS) * 1.1, 4),
48-
}
49-
)
50-
trackio.finish()
32+
trackio.init(project=PROJECT, name="run-0", config={"lr": 0.001, "epochs": EPOCHS})
33+
for epoch in range(EPOCHS):
34+
loss, acc = fake_metrics(epoch, EPOCHS)
35+
trackio.log({"train/loss": loss, "train/accuracy": acc})
36+
trackio.finish()
5137

38+
print("First run complete. Syncing to a static Space...")
5239
space_id = trackio.sync(project=PROJECT, sdk="static")
5340
print(f"Dashboard: https://huggingface.co/spaces/{space_id}")
41+
42+
trackio.init(project=PROJECT, name="run-1", config={"lr": 0.003, "epochs": EPOCHS})
43+
for epoch in range(EPOCHS):
44+
loss, acc = fake_metrics(epoch, EPOCHS)
45+
trackio.log({"train/loss": loss, "train/accuracy": acc})
46+
trackio.finish()
47+
48+
print("Second run complete. Syncing again...")
49+
trackio.sync(project=PROJECT, sdk="static")
50+
print("Static Space updated with both runs.")

examples/transformers-integration.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# /// script
22
# dependencies = [
3-
# "trackio>=0.14.2",
3+
# "trackio>=0.22.0",
44
# "datasets>=4.4.0",
55
# "transformers[torch]>=5.0.0rc2",
66
# "huggingface_hub>=1.0.0",
@@ -26,9 +26,11 @@
2626
encodings = tokenizer(texts, truncation=True, padding=True, max_length=64)
2727
dataset = Dataset.from_dict({**encodings, "labels": labels})
2828

29-
username = huggingface_hub.whoami()["name"]
29+
username = huggingface_hub.whoami(cache=True)["name"]
3030
hub_model_id = f"{username}/trackio-transformers-demo"
3131

32+
# Local Trackio logs by default; the first Hub push runs sync(sdk="static") and links the dashboard on the model card.
33+
3234
trainer = Trainer(
3335
model=model,
3436
args=TrainingArguments(

0 commit comments

Comments
 (0)