abidlabs HF Staff commited on
Commit
a9ee714
·
verified ·
1 Parent(s): 431c34c

Upload folder using huggingface_hub

Browse files
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ trackio_logo.png filter=lfs diff=lfs merge=lfs -text
__init__.py ADDED
@@ -0,0 +1,155 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import contextvars
2
+ import time
3
+ import webbrowser
4
+ from pathlib import Path
5
+
6
+ import huggingface_hub
7
+ from gradio_client import Client
8
+ from httpx import ReadTimeout
9
+ from huggingface_hub.errors import RepositoryNotFoundError
10
+
11
+ from trackio.deploy import deploy_as_space
12
+ from trackio.run import Run
13
+ from trackio.ui import demo
14
+ from trackio.utils import TRACKIO_DIR, TRACKIO_LOGO_PATH, block_except_in_notebook
15
+
16
+ __version__ = Path(__file__).parent.joinpath("version.txt").read_text().strip()
17
+
18
+
19
+ current_run: contextvars.ContextVar[Run | None] = contextvars.ContextVar(
20
+ "current_run", default=None
21
+ )
22
+ current_project: contextvars.ContextVar[str | None] = contextvars.ContextVar(
23
+ "current_project", default=None
24
+ )
25
+ current_server: contextvars.ContextVar[str | None] = contextvars.ContextVar(
26
+ "current_server", default=None
27
+ )
28
+
29
+ config = {}
30
+ SPACE_URL = "https://huggingface.co/spaces/{space_id}"
31
+
32
+
33
+ def init(
34
+ project: str,
35
+ name: str | None = None,
36
+ space_id: str | None = None,
37
+ config: dict | None = None,
38
+ ) -> Run:
39
+ """
40
+ Creates a new Trackio project and returns a Run object.
41
+
42
+ Args:
43
+ project: The name of the project (can be an existing project to continue tracking or a new project to start tracking from scratch).
44
+ name: The name of the run (if not provided, a default name will be generated).
45
+ space_id: If provided, the project will be logged to a Hugging Face Space instead of a local directory. Should be a complete Space name like "username/reponame". If the Space does not exist, it will be created. If the Space already exists, the project will be logged to it.
46
+ config: A dictionary of configuration options. Provided for compatibility with wandb.init()
47
+ """
48
+ if not current_server.get() and space_id is None:
49
+ _, url, _ = demo.launch(
50
+ show_api=False, inline=False, quiet=True, prevent_thread_lock=True
51
+ )
52
+ current_server.set(url)
53
+ else:
54
+ url = current_server.get()
55
+
56
+ if current_project.get() is None or current_project.get() != project:
57
+ print(f"* Trackio project initialized: {project}")
58
+
59
+ if space_id is None:
60
+ print(f"* Trackio metrics logged to: {TRACKIO_DIR}")
61
+ print(
62
+ f'\n* View dashboard by running in your terminal: trackio show --project "{project}"'
63
+ )
64
+ print(f'* or by running in Python: trackio.show(project="{project}")')
65
+ else:
66
+ create_space_if_not_exists(space_id)
67
+ print(
68
+ f"* View dashboard by going to: {SPACE_URL.format(space_id=space_id)}"
69
+ )
70
+ current_project.set(project)
71
+
72
+ space_or_url = space_id if space_id else url
73
+ client = Client(space_or_url, verbose=False)
74
+ run = Run(project=project, client=client, name=name, config=config)
75
+ current_run.set(run)
76
+ globals()["config"] = run.config
77
+ return run
78
+
79
+
80
+ def create_space_if_not_exists(space_id: str) -> None:
81
+ """
82
+ Creates a new Hugging Face Space if it does not exist.
83
+
84
+ Args:
85
+ space_id: The ID of the Space to create.
86
+ """
87
+ if "/" not in space_id:
88
+ raise ValueError(
89
+ f"Invalid space ID: {space_id}. Must be in the format: username/reponame."
90
+ )
91
+ try:
92
+ huggingface_hub.repo_info(space_id, repo_type="space")
93
+ print(f"* Found existing space: {SPACE_URL.format(space_id=space_id)}")
94
+ return
95
+ except RepositoryNotFoundError:
96
+ pass
97
+
98
+ print(f"* Creating new space: {SPACE_URL.format(space_id=space_id)}")
99
+ deploy_as_space(space_id)
100
+
101
+ client = None
102
+ for _ in range(30):
103
+ try:
104
+ client = Client(space_id, verbose=False)
105
+ if client:
106
+ break
107
+ except ReadTimeout:
108
+ print("* Space is not yet ready. Waiting 5 seconds...")
109
+ time.sleep(5)
110
+ except ValueError as e:
111
+ print(f"* Space gave error {e}. Trying again in 5 seconds...")
112
+ time.sleep(5)
113
+
114
+
115
+ def log(metrics: dict) -> None:
116
+ """
117
+ Logs metrics to the current run.
118
+
119
+ Args:
120
+ metrics: A dictionary of metrics to log.
121
+ """
122
+ if current_run.get() is None:
123
+ raise RuntimeError("Call trackio.init() before log().")
124
+ current_run.get().log(metrics)
125
+
126
+
127
+ def finish():
128
+ """
129
+ Finishes the current run.
130
+ """
131
+ if current_run.get() is None:
132
+ raise RuntimeError("Call trackio.init() before finish().")
133
+ current_run.get().finish()
134
+
135
+
136
+ def show(project: str | None = None):
137
+ """
138
+ Launches the Trackio dashboard.
139
+
140
+ Args:
141
+ project: The name of the project whose runs to show. If not provided, all projects will be shown and the user can select one.
142
+ """
143
+ _, url, share_url = demo.launch(
144
+ show_api=False,
145
+ quiet=True,
146
+ inline=False,
147
+ prevent_thread_lock=True,
148
+ favicon_path=TRACKIO_LOGO_PATH,
149
+ allowed_paths=[TRACKIO_LOGO_PATH],
150
+ )
151
+ base_url = share_url + "/" if share_url else url
152
+ dashboard_url = base_url + f"?project={project}" if project else base_url
153
+ print(f"* Trackio UI launched at: {dashboard_url}")
154
+ webbrowser.open(dashboard_url)
155
+ block_except_in_notebook()
__pycache__/__init__.cpython-312.pyc ADDED
Binary file (7.1 kB). View file
 
__pycache__/cli.cpython-312.pyc ADDED
Binary file (1.11 kB). View file
 
__pycache__/context.cpython-312.pyc ADDED
Binary file (440 Bytes). View file
 
__pycache__/deploy.cpython-312.pyc ADDED
Binary file (2.27 kB). View file
 
__pycache__/run.cpython-312.pyc ADDED
Binary file (1.28 kB). View file
 
__pycache__/sqlite_storage.cpython-312.pyc ADDED
Binary file (6.72 kB). View file
 
__pycache__/storage.cpython-312.pyc ADDED
Binary file (4.6 kB). View file
 
__pycache__/ui.cpython-312.pyc ADDED
Binary file (9.32 kB). View file
 
__pycache__/utils.cpython-312.pyc ADDED
Binary file (3.18 kB). View file
 
cli.py ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import argparse
2
+
3
+ from trackio import show
4
+
5
+
6
+ def main():
7
+ parser = argparse.ArgumentParser(description="Trackio CLI")
8
+ subparsers = parser.add_subparsers(dest="command")
9
+
10
+ ui_parser = subparsers.add_parser(
11
+ "show", help="Show the Trackio dashboard UI for a project"
12
+ )
13
+ ui_parser.add_argument(
14
+ "--project", required=False, help="Project name to show in the dashboard"
15
+ )
16
+
17
+ args = parser.parse_args()
18
+
19
+ if args.command == "show":
20
+ show(args.project)
21
+ else:
22
+ parser.print_help()
23
+
24
+
25
+ if __name__ == "__main__":
26
+ main()
deploy.py ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import io
2
+ import os
3
+ from importlib.resources import files
4
+ from pathlib import Path
5
+
6
+ import gradio
7
+ import huggingface_hub
8
+
9
+
10
+ def deploy_as_space(title: str):
11
+ if (
12
+ os.getenv("SYSTEM") == "spaces"
13
+ ): # in case a repo with this function is uploaded to spaces
14
+ return
15
+
16
+ trackio_path = files("trackio")
17
+
18
+ hf_api = huggingface_hub.HfApi()
19
+ whoami = None
20
+ login = False
21
+ try:
22
+ whoami = hf_api.whoami()
23
+ if whoami["auth"]["accessToken"]["role"] != "write":
24
+ login = True
25
+ except OSError:
26
+ login = True
27
+ if login:
28
+ print("Need 'write' access token to create a Spaces repo.")
29
+ huggingface_hub.login(add_to_git_credential=False)
30
+ whoami = hf_api.whoami()
31
+
32
+ space_id = huggingface_hub.create_repo(
33
+ title,
34
+ space_sdk="gradio",
35
+ repo_type="space",
36
+ exist_ok=True,
37
+ ).repo_id
38
+ assert space_id == title # not sure why these would differ
39
+
40
+ with open(Path(trackio_path, "README.md"), "r") as f:
41
+ readme_content = f.read()
42
+ readme_content = readme_content.replace("{GRADIO_VERSION}", gradio.__version__)
43
+ readme_buffer = io.BytesIO(readme_content.encode("utf-8"))
44
+ hf_api.upload_file(
45
+ path_or_fileobj=readme_buffer,
46
+ path_in_repo="README.md",
47
+ repo_id=space_id,
48
+ repo_type="space",
49
+ )
50
+
51
+ huggingface_hub.utils.disable_progress_bars()
52
+ hf_api.upload_folder(
53
+ repo_id=space_id,
54
+ repo_type="space",
55
+ folder_path=trackio_path,
56
+ ignore_patterns=["README.md"],
57
+ )
run.py ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from gradio_client import Client
2
+
3
+ from trackio.utils import generate_readable_name
4
+
5
+
6
+ class Run:
7
+ def __init__(
8
+ self,
9
+ project: str,
10
+ client: Client,
11
+ name: str | None = None,
12
+ config: dict | None = None,
13
+ ):
14
+ self.project = project
15
+ self.client = client
16
+ self.name = name or generate_readable_name()
17
+ self.config = config or {}
18
+
19
+ def log(self, metrics: dict):
20
+ self.client.predict(
21
+ api_name="/log", project=self.project, run=self.name, metrics=metrics
22
+ )
23
+
24
+ def finish(self):
25
+ pass
sqlite_storage.py ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import os
3
+ import sqlite3
4
+
5
+ try:
6
+ from trackio.utils import RESERVED_KEYS, TRACKIO_DIR
7
+ except: # noqa: E722
8
+ from utils import RESERVED_KEYS, TRACKIO_DIR
9
+
10
+
11
+ class SQLiteStorage:
12
+ def __init__(self, project: str, name: str, config: dict):
13
+ self.project = project
14
+ self.name = name
15
+ self.config = config
16
+ self.db_path = os.path.join(TRACKIO_DIR, "trackio.db")
17
+
18
+ os.makedirs(TRACKIO_DIR, exist_ok=True)
19
+
20
+ self._init_db()
21
+ self._save_config()
22
+
23
+ def _init_db(self):
24
+ """Initialize the SQLite database with required tables."""
25
+ with sqlite3.connect(self.db_path) as conn:
26
+ cursor = conn.cursor()
27
+
28
+ cursor.execute("""
29
+ CREATE TABLE IF NOT EXISTS metrics (
30
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
31
+ timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
32
+ project_name TEXT NOT NULL,
33
+ run_name TEXT NOT NULL,
34
+ metrics TEXT NOT NULL
35
+ )
36
+ """)
37
+
38
+ cursor.execute("""
39
+ CREATE TABLE IF NOT EXISTS configs (
40
+ project_name TEXT NOT NULL,
41
+ run_name TEXT NOT NULL,
42
+ config TEXT NOT NULL,
43
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
44
+ PRIMARY KEY (project_name, run_name)
45
+ )
46
+ """)
47
+
48
+ conn.commit()
49
+
50
+ def _save_config(self):
51
+ """Save the run configuration to the database."""
52
+ with sqlite3.connect(self.db_path) as conn:
53
+ cursor = conn.cursor()
54
+ cursor.execute(
55
+ "INSERT OR REPLACE INTO configs (project_name, run_name, config) VALUES (?, ?, ?)",
56
+ (self.project, self.name, json.dumps(self.config)),
57
+ )
58
+ conn.commit()
59
+
60
+ def log(self, metrics: dict):
61
+ """Log metrics to the database."""
62
+ for k in metrics.keys():
63
+ if k in RESERVED_KEYS or k.startswith("__"):
64
+ raise ValueError(
65
+ f"Please do not use this reserved key as a metric: {k}"
66
+ )
67
+
68
+ with sqlite3.connect(self.db_path) as conn:
69
+ cursor = conn.cursor()
70
+ cursor.execute(
71
+ """
72
+ INSERT INTO metrics
73
+ (project_name, run_name, metrics)
74
+ VALUES (?, ?, ?)
75
+ """,
76
+ (self.project, self.name, json.dumps(metrics)),
77
+ )
78
+ conn.commit()
79
+
80
+ def get_metrics(self, project: str, run: str) -> list[dict]:
81
+ """Retrieve metrics for a specific run."""
82
+ with sqlite3.connect(self.db_path) as conn:
83
+ cursor = conn.cursor()
84
+ cursor.execute(
85
+ """
86
+ SELECT timestamp, metrics
87
+ FROM metrics
88
+ WHERE project_name = ? AND run_name = ?
89
+ ORDER BY timestamp
90
+ """,
91
+ (project, run),
92
+ )
93
+ rows = cursor.fetchall()
94
+
95
+ results = []
96
+ for row in rows:
97
+ timestamp, metrics_json = row
98
+ metrics = json.loads(metrics_json)
99
+ metrics["timestamp"] = timestamp
100
+ results.append(metrics)
101
+
102
+ return results
103
+
104
+ def get_projects(self) -> list[str]:
105
+ """Get list of all projects."""
106
+ with sqlite3.connect(self.db_path) as conn:
107
+ cursor = conn.cursor()
108
+ cursor.execute("SELECT DISTINCT project_name FROM metrics")
109
+ return [row[0] for row in cursor.fetchall()]
110
+
111
+ def get_runs(self, project: str) -> list[str]:
112
+ """Get list of all runs for a project."""
113
+ with sqlite3.connect(self.db_path) as conn:
114
+ cursor = conn.cursor()
115
+ cursor.execute(
116
+ "SELECT DISTINCT run_name FROM metrics WHERE project_name = ?",
117
+ (project,),
118
+ )
119
+ return [row[0] for row in cursor.fetchall()]
120
+
121
+ def finish(self):
122
+ """Cleanup when run is finished."""
123
+ pass
trackio_logo.png ADDED

Git LFS Details

  • SHA256: 3922c4d1e465270ad4d8abb12023f3beed5d9f7f338528a4c0ac21dcf358a1c8
  • Pointer size: 131 Bytes
  • Size of remote file: 487 kB
ui.py ADDED
@@ -0,0 +1,214 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Any
2
+
3
+ import gradio as gr
4
+ import pandas as pd
5
+
6
+ try:
7
+ from trackio.sqlite_storage import SQLiteStorage
8
+ from trackio.utils import RESERVED_KEYS, TRACKIO_LOGO_PATH
9
+ except: # noqa: E722
10
+ from sqlite_storage import SQLiteStorage
11
+ from utils import RESERVED_KEYS, TRACKIO_LOGO_PATH
12
+
13
+
14
+ def get_projects(request: gr.Request):
15
+ storage = SQLiteStorage("", "", {})
16
+ projects = storage.get_projects()
17
+ if project := request.query_params.get("project"):
18
+ interactive = False
19
+ else:
20
+ interactive = True
21
+ project = projects[0] if projects else None
22
+ return gr.Dropdown(
23
+ label="Project",
24
+ choices=projects,
25
+ value=project,
26
+ allow_custom_value=True,
27
+ interactive=interactive,
28
+ )
29
+
30
+
31
+ def get_runs(project):
32
+ if not project:
33
+ return []
34
+ storage = SQLiteStorage("", "", {})
35
+ return storage.get_runs(project)
36
+
37
+
38
+ def load_run_data(project: str | None, run: str | None, smoothing: bool):
39
+ if not project or not run:
40
+ return None
41
+ storage = SQLiteStorage("", "", {})
42
+ metrics = storage.get_metrics(project, run)
43
+ if not metrics:
44
+ return None
45
+ df = pd.DataFrame(metrics)
46
+ if smoothing:
47
+ numeric_cols = df.select_dtypes(include="number").columns
48
+ numeric_cols = [c for c in numeric_cols if c not in RESERVED_KEYS]
49
+ df[numeric_cols] = df[numeric_cols].ewm(alpha=0.1).mean()
50
+ if "step" not in df.columns:
51
+ df["step"] = range(len(df))
52
+ return df
53
+
54
+
55
+ def update_runs(project, filter_text, user_interacted_with_runs=False):
56
+ if project is None:
57
+ runs = []
58
+ else:
59
+ runs = get_runs(project)
60
+ if filter_text:
61
+ runs = [r for r in runs if filter_text in r]
62
+ if not user_interacted_with_runs:
63
+ return gr.CheckboxGroup(choices=runs, value=runs)
64
+ else:
65
+ return gr.CheckboxGroup(choices=runs)
66
+
67
+
68
+ def filter_runs(project, filter_text):
69
+ runs = get_runs(project)
70
+ runs = [r for r in runs if filter_text in r]
71
+ return gr.CheckboxGroup(choices=runs, value=runs)
72
+
73
+
74
+ def toggle_timer(cb_value):
75
+ if cb_value:
76
+ return gr.Timer(active=True)
77
+ else:
78
+ return gr.Timer(active=False)
79
+
80
+
81
+ def log(project: str, run: str, metrics: dict[str, Any]) -> None:
82
+ storage = SQLiteStorage(project, run, {})
83
+ storage.log(metrics)
84
+
85
+
86
+ def configure(request: gr.Request):
87
+ if metrics := request.query_params.get("metrics"):
88
+ return metrics.split(",")
89
+ else:
90
+ return []
91
+
92
+
93
+ with gr.Blocks(theme="citrus", title="Trackio Dashboard") as demo:
94
+ with gr.Sidebar() as sidebar:
95
+ gr.Markdown(
96
+ f"<div style='display: flex; align-items: center; gap: 8px;'><img src='/gradio_api/file={TRACKIO_LOGO_PATH}' width='32' height='32'><span style='font-size: 2em; font-weight: bold;'>Trackio</span></div>"
97
+ )
98
+ project_dd = gr.Dropdown(label="Project")
99
+ run_tb = gr.Textbox(label="Runs (99)", placeholder="Type to filter...")
100
+ run_cb = gr.CheckboxGroup(label="Runs", choices=[], interactive=True)
101
+ with gr.Sidebar(position="right", open=False) as settings_sidebar:
102
+ gr.Markdown("### ⚙️ Settings")
103
+ realtime_cb = gr.Checkbox(label="Refresh realtime", value=True)
104
+ smoothing_cb = gr.Checkbox(label="Smoothing", value=True)
105
+
106
+ timer = gr.Timer(value=1)
107
+ metrics_subset = gr.State([])
108
+ user_interacted_with_run_cb = gr.State(False)
109
+
110
+ gr.on(
111
+ [demo.load],
112
+ fn=configure,
113
+ outputs=metrics_subset,
114
+ )
115
+ gr.on(
116
+ [demo.load],
117
+ fn=get_projects,
118
+ outputs=project_dd,
119
+ show_progress="hidden",
120
+ )
121
+ gr.on(
122
+ [timer.tick],
123
+ fn=update_runs,
124
+ inputs=[project_dd, run_tb, user_interacted_with_run_cb],
125
+ outputs=run_cb,
126
+ show_progress="hidden",
127
+ )
128
+ gr.on(
129
+ [demo.load, project_dd.change],
130
+ fn=update_runs,
131
+ inputs=[project_dd, run_tb],
132
+ outputs=run_cb,
133
+ show_progress="hidden",
134
+ )
135
+
136
+ realtime_cb.change(
137
+ fn=toggle_timer,
138
+ inputs=realtime_cb,
139
+ outputs=timer,
140
+ api_name="toggle_timer",
141
+ )
142
+ run_cb.input(
143
+ fn=lambda: True,
144
+ outputs=user_interacted_with_run_cb,
145
+ )
146
+ run_tb.input(
147
+ fn=filter_runs,
148
+ inputs=[project_dd, run_tb],
149
+ outputs=run_cb,
150
+ )
151
+
152
+ gr.api(
153
+ fn=log,
154
+ api_name="log",
155
+ )
156
+
157
+ x_lim = gr.State(None)
158
+
159
+ def update_x_lim(select_data: gr.SelectData):
160
+ return select_data.index
161
+
162
+ @gr.render(
163
+ triggers=[
164
+ demo.load,
165
+ run_cb.change,
166
+ timer.tick,
167
+ smoothing_cb.change,
168
+ x_lim.change,
169
+ ],
170
+ inputs=[project_dd, run_cb, smoothing_cb, metrics_subset, x_lim],
171
+ )
172
+ def update_dashboard(project, runs, smoothing, metrics_subset, x_lim_value):
173
+ dfs = []
174
+ for run in runs:
175
+ df = load_run_data(project, run, smoothing)
176
+ if df is not None:
177
+ df["run"] = run
178
+ dfs.append(df)
179
+ if dfs:
180
+ master_df = pd.concat(dfs, ignore_index=True)
181
+ else:
182
+ master_df = pd.DataFrame()
183
+ numeric_cols = master_df.select_dtypes(include="number").columns
184
+ numeric_cols = [c for c in numeric_cols if c not in RESERVED_KEYS]
185
+ if metrics_subset:
186
+ numeric_cols = [c for c in numeric_cols if c in metrics_subset]
187
+ plots: list[gr.LinePlot] = []
188
+ for col in range(len(numeric_cols) // 2):
189
+ with gr.Row(key=f"row-{col}"):
190
+ for i in range(2):
191
+ plot = gr.LinePlot(
192
+ master_df,
193
+ x="step",
194
+ y=numeric_cols[2 * col + i],
195
+ color="run" if "run" in master_df.columns else None,
196
+ title=numeric_cols[2 * col + i],
197
+ key=f"plot-{col}-{i}",
198
+ preserved_by_key=None,
199
+ x_lim=x_lim_value,
200
+ y_lim=[
201
+ min(master_df[numeric_cols[2 * col + i]]),
202
+ max(master_df[numeric_cols[2 * col + i]]),
203
+ ],
204
+ show_fullscreen_button=True,
205
+ )
206
+ plots.append(plot)
207
+
208
+ for plot in plots:
209
+ plot.select(update_x_lim, outputs=x_lim)
210
+ plot.double_click(lambda: None, outputs=x_lim)
211
+
212
+
213
+ if __name__ == "__main__":
214
+ demo.launch(allowed_paths=[TRACKIO_LOGO_PATH], show_api=False)
utils.py ADDED
@@ -0,0 +1,217 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import random
3
+ import sys
4
+ import time
5
+ from pathlib import Path
6
+
7
+ from huggingface_hub.constants import HF_HOME
8
+
9
+ RESERVED_KEYS = ["project", "run", "timestamp"]
10
+ TRACKIO_DIR = os.path.join(HF_HOME, "trackio")
11
+
12
+ TRACKIO_LOGO_PATH = str(Path(__file__).parent.joinpath("trackio_logo.png"))
13
+
14
+
15
+ def generate_readable_name():
16
+ """
17
+ Generates a random, readable name like "dainty-sunset-1"
18
+ """
19
+ adjectives = [
20
+ "dainty",
21
+ "brave",
22
+ "calm",
23
+ "eager",
24
+ "fancy",
25
+ "gentle",
26
+ "happy",
27
+ "jolly",
28
+ "kind",
29
+ "lively",
30
+ "merry",
31
+ "nice",
32
+ "proud",
33
+ "quick",
34
+ "silly",
35
+ "tidy",
36
+ "witty",
37
+ "zealous",
38
+ "bright",
39
+ "shy",
40
+ "bold",
41
+ "clever",
42
+ "daring",
43
+ "elegant",
44
+ "faithful",
45
+ "graceful",
46
+ "honest",
47
+ "inventive",
48
+ "jovial",
49
+ "keen",
50
+ "lucky",
51
+ "modest",
52
+ "noble",
53
+ "optimistic",
54
+ "patient",
55
+ "quirky",
56
+ "resourceful",
57
+ "sincere",
58
+ "thoughtful",
59
+ "upbeat",
60
+ "valiant",
61
+ "warm",
62
+ "youthful",
63
+ "zesty",
64
+ "adventurous",
65
+ "breezy",
66
+ "cheerful",
67
+ "delightful",
68
+ "energetic",
69
+ "fearless",
70
+ "glad",
71
+ "hopeful",
72
+ "imaginative",
73
+ "joyful",
74
+ "kindly",
75
+ "luminous",
76
+ "mysterious",
77
+ "neat",
78
+ "outgoing",
79
+ "playful",
80
+ "radiant",
81
+ "spirited",
82
+ "tranquil",
83
+ "unique",
84
+ "vivid",
85
+ "wise",
86
+ "zany",
87
+ "artful",
88
+ "bubbly",
89
+ "charming",
90
+ "dazzling",
91
+ "earnest",
92
+ "festive",
93
+ "gentlemanly",
94
+ "hearty",
95
+ "intrepid",
96
+ "jubilant",
97
+ "knightly",
98
+ "lively",
99
+ "magnetic",
100
+ "nimble",
101
+ "orderly",
102
+ "peaceful",
103
+ "quick-witted",
104
+ "robust",
105
+ "sturdy",
106
+ "trusty",
107
+ "upstanding",
108
+ "vibrant",
109
+ "whimsical",
110
+ ]
111
+ nouns = [
112
+ "sunset",
113
+ "forest",
114
+ "river",
115
+ "mountain",
116
+ "breeze",
117
+ "meadow",
118
+ "ocean",
119
+ "valley",
120
+ "sky",
121
+ "field",
122
+ "cloud",
123
+ "star",
124
+ "rain",
125
+ "leaf",
126
+ "stone",
127
+ "flower",
128
+ "bird",
129
+ "tree",
130
+ "wave",
131
+ "trail",
132
+ "island",
133
+ "desert",
134
+ "hill",
135
+ "lake",
136
+ "pond",
137
+ "grove",
138
+ "canyon",
139
+ "reef",
140
+ "bay",
141
+ "peak",
142
+ "glade",
143
+ "marsh",
144
+ "cliff",
145
+ "dune",
146
+ "spring",
147
+ "brook",
148
+ "cave",
149
+ "plain",
150
+ "ridge",
151
+ "wood",
152
+ "blossom",
153
+ "petal",
154
+ "root",
155
+ "branch",
156
+ "seed",
157
+ "acorn",
158
+ "pine",
159
+ "willow",
160
+ "cedar",
161
+ "elm",
162
+ "falcon",
163
+ "eagle",
164
+ "sparrow",
165
+ "robin",
166
+ "owl",
167
+ "finch",
168
+ "heron",
169
+ "crane",
170
+ "duck",
171
+ "swan",
172
+ "fox",
173
+ "wolf",
174
+ "bear",
175
+ "deer",
176
+ "moose",
177
+ "otter",
178
+ "beaver",
179
+ "lynx",
180
+ "hare",
181
+ "badger",
182
+ "butterfly",
183
+ "bee",
184
+ "ant",
185
+ "beetle",
186
+ "dragonfly",
187
+ "firefly",
188
+ "ladybug",
189
+ "moth",
190
+ "spider",
191
+ "worm",
192
+ "coral",
193
+ "kelp",
194
+ "shell",
195
+ "pebble",
196
+ "boulder",
197
+ "cobble",
198
+ "sand",
199
+ "wavelet",
200
+ "tide",
201
+ "current",
202
+ ]
203
+ adjective = random.choice(adjectives)
204
+ noun = random.choice(nouns)
205
+ number = random.randint(1, 99)
206
+ return f"{adjective}-{noun}-{number}"
207
+
208
+
209
+ def block_except_in_notebook():
210
+ in_notebook = bool(getattr(sys, "ps1", sys.flags.interactive))
211
+ if in_notebook:
212
+ return
213
+ try:
214
+ while True:
215
+ time.sleep(0.1)
216
+ except (KeyboardInterrupt, OSError):
217
+ print("Keyboard interruption in main thread... closing dashboard.")
version.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ 0.0.8