qgallouedec HF Staff commited on
Commit
1445d6c
·
verified ·
1 Parent(s): 19be7f0

Upload folder using huggingface_hub

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +1 -0
  2. trackio/CHANGELOG.md +160 -0
  3. trackio/__init__.py +664 -0
  4. trackio/__pycache__/__init__.cpython-312.pyc +0 -0
  5. trackio/__pycache__/__init__.cpython-313.pyc +0 -0
  6. trackio/__pycache__/alerts.cpython-313.pyc +0 -0
  7. trackio/__pycache__/api.cpython-312.pyc +0 -0
  8. trackio/__pycache__/api.cpython-313.pyc +0 -0
  9. trackio/__pycache__/cli.cpython-312.pyc +0 -0
  10. trackio/__pycache__/cli.cpython-313.pyc +0 -0
  11. trackio/__pycache__/cli_helpers.cpython-313.pyc +0 -0
  12. trackio/__pycache__/commit_scheduler.cpython-312.pyc +0 -0
  13. trackio/__pycache__/commit_scheduler.cpython-313.pyc +0 -0
  14. trackio/__pycache__/context_vars.cpython-312.pyc +0 -0
  15. trackio/__pycache__/context_vars.cpython-313.pyc +0 -0
  16. trackio/__pycache__/deploy.cpython-312.pyc +0 -0
  17. trackio/__pycache__/deploy.cpython-313.pyc +0 -0
  18. trackio/__pycache__/dummy_commit_scheduler.cpython-312.pyc +0 -0
  19. trackio/__pycache__/dummy_commit_scheduler.cpython-313.pyc +0 -0
  20. trackio/__pycache__/file_storage.cpython-312.pyc +0 -0
  21. trackio/__pycache__/gpu.cpython-312.pyc +0 -0
  22. trackio/__pycache__/gpu.cpython-313.pyc +0 -0
  23. trackio/__pycache__/histogram.cpython-312.pyc +0 -0
  24. trackio/__pycache__/histogram.cpython-313.pyc +0 -0
  25. trackio/__pycache__/imports.cpython-312.pyc +0 -0
  26. trackio/__pycache__/imports.cpython-313.pyc +0 -0
  27. trackio/__pycache__/markdown.cpython-313.pyc +0 -0
  28. trackio/__pycache__/media.cpython-312.pyc +0 -0
  29. trackio/__pycache__/run.cpython-312.pyc +0 -0
  30. trackio/__pycache__/run.cpython-313.pyc +0 -0
  31. trackio/__pycache__/sqlite_storage.cpython-312.pyc +0 -0
  32. trackio/__pycache__/sqlite_storage.cpython-313.pyc +0 -0
  33. trackio/__pycache__/table.cpython-312.pyc +0 -0
  34. trackio/__pycache__/table.cpython-313.pyc +0 -0
  35. trackio/__pycache__/typehints.cpython-312.pyc +0 -0
  36. trackio/__pycache__/typehints.cpython-313.pyc +0 -0
  37. trackio/__pycache__/ui.cpython-312.pyc +0 -0
  38. trackio/__pycache__/utils.cpython-312.pyc +0 -0
  39. trackio/__pycache__/utils.cpython-313.pyc +0 -0
  40. trackio/__pycache__/video_writer.cpython-312.pyc +0 -0
  41. trackio/alerts.py +185 -0
  42. trackio/api.py +87 -0
  43. trackio/assets/badge.png +0 -0
  44. trackio/assets/trackio_logo_dark.png +0 -0
  45. trackio/assets/trackio_logo_light.png +0 -0
  46. trackio/assets/trackio_logo_old.png +3 -0
  47. trackio/assets/trackio_logo_type_dark.png +0 -0
  48. trackio/assets/trackio_logo_type_dark_transparent.png +0 -0
  49. trackio/assets/trackio_logo_type_light.png +0 -0
  50. trackio/assets/trackio_logo_type_light_transparent.png +0 -0
.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/assets/trackio_logo_old.png filter=lfs diff=lfs merge=lfs -text
trackio/CHANGELOG.md ADDED
@@ -0,0 +1,160 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # trackio
2
+
3
+ ## 0.17.0
4
+
5
+ ### Features
6
+
7
+ - [#428](https://github.com/gradio-app/trackio/pull/428) [`f7dd1ce`](https://github.com/gradio-app/trackio/commit/f7dd1ce2dc8a1936f9983467fcbcf93bfef01e09) - feat: add ability to rename runs. Thanks @Saba9!
8
+ - [#437](https://github.com/gradio-app/trackio/pull/437) [`2727c0b`](https://github.com/gradio-app/trackio/commit/2727c0b0755f48f7f186162ea45185c98f6b5516) - Add markdown reports across Trackio. Thanks @abidlabs!
9
+ - [#427](https://github.com/gradio-app/trackio/pull/427) [`5aeb9ed`](https://github.com/gradio-app/trackio/commit/5aeb9edcfd2068d309d9d64f172dcbcc327be1ab) - Make Trackio logging much more robust. Thanks @abidlabs!
10
+
11
+ ## 0.16.1
12
+
13
+ ### Features
14
+
15
+ - [#431](https://github.com/gradio-app/trackio/pull/431) [`c7ce55b`](https://github.com/gradio-app/trackio/commit/c7ce55b14dd5eb0c2165fb15df17dd60721c9325) - Lazy load the UI when trackio is imported. Thanks @abidlabs!
16
+
17
+ ## 0.16.0
18
+
19
+ ### Features
20
+
21
+ - [#426](https://github.com/gradio-app/trackio/pull/426) [`ead4dc8`](https://github.com/gradio-app/trackio/commit/ead4dc8e74ee2d8e47d61bca0a7668456acf49be) - Fix redundant double rendering of group checkboxes. Thanks @abidlabs!
22
+ - [#413](https://github.com/gradio-app/trackio/pull/413) [`39c4750`](https://github.com/gradio-app/trackio/commit/39c4750951d554ba6eb4d58847c6bb444b2891a8) - Check `dist-packages` when checking for source installation. Thanks @sergiopaniego!
23
+ - [#423](https://github.com/gradio-app/trackio/pull/423) [`2e52ab3`](https://github.com/gradio-app/trackio/commit/2e52ab303e3041718a6a56fbf84d0848aca9ad67) - Fix legend outline visibility issue. Thanks @Raghunath-Balaji!
24
+ - [#407](https://github.com/gradio-app/trackio/pull/407) [`c8a384d`](https://github.com/gradio-app/trackio/commit/c8a384ddfe5a295cecf862a26178d40e48acb424) - Fix pytests that were failling locally on MacOS. Thanks @abidlabs!
25
+ - [#405](https://github.com/gradio-app/trackio/pull/405) [`35aae4e`](https://github.com/gradio-app/trackio/commit/35aae4e3aa3e2b2888887528478b9dc6a9808bda) - Add conditional padding for HF Space dashboard when not in iframe. Thanks @znation!
26
+
27
+ ## 0.15.0
28
+
29
+ ### Features
30
+
31
+ - [#397](https://github.com/gradio-app/trackio/pull/397) [`6b38ad0`](https://github.com/gradio-app/trackio/commit/6b38ad02e5d73a0df49c4eede7e91331282ece04) - Adds `--host` cli option support. Thanks @abidlabs!
32
+ - [#396](https://github.com/gradio-app/trackio/pull/396) [`4a4d1ab`](https://github.com/gradio-app/trackio/commit/4a4d1ab85e63d923132a3fa7afa5d90e16431bec) - Fix run selection issue. Thanks @abidlabs!
33
+ - [#394](https://github.com/gradio-app/trackio/pull/394) [`c47a3a3`](https://github.com/gradio-app/trackio/commit/c47a3a31f8c4b83bce1aa7fc22eeba3d9021ad3d) - Add wandb-compatible API for trackio. Thanks @abidlabs!
34
+ - [#378](https://github.com/gradio-app/trackio/pull/378) [`b02046a`](https://github.com/gradio-app/trackio/commit/b02046a5b0dad7c9854e099a87f884afba4aecb2) - Add JSON export button for line plots and upgrade gradio dependency. Thanks @JamshedAli18!
35
+
36
+ ## 0.14.2
37
+
38
+ ### Features
39
+
40
+ - [#386](https://github.com/gradio-app/trackio/pull/386) [`f9452cd`](https://github.com/gradio-app/trackio/commit/f9452cdb8f0819368f3610f7ac0ed08957305275) - Fixing some issues related to deployed Trackio Spaces. Thanks @abidlabs!
41
+
42
+ ## 0.14.1
43
+
44
+ ### Features
45
+
46
+ - [#382](https://github.com/gradio-app/trackio/pull/382) [`44fe9bb`](https://github.com/gradio-app/trackio/commit/44fe9bb264fb2aafb0ec302ff15227c045819a2c) - Fix app file path when Trackio is not installed from source. Thanks @abidlabs!
47
+ - [#380](https://github.com/gradio-app/trackio/pull/380) [`c3f4cff`](https://github.com/gradio-app/trackio/commit/c3f4cff74bc5676e812773d8571454894fcdc7cc) - Add CLI commands for querying projects, runs, and metrics. Thanks @abidlabs!
48
+
49
+ ## 0.14.0
50
+
51
+ ### Features
52
+
53
+ - [#377](https://github.com/gradio-app/trackio/pull/377) [`5c5015b`](https://github.com/gradio-app/trackio/commit/5c5015b68c85c5de51111dad983f735c27b9a05f) - fixed wrapping issue in Runs table. Thanks @gaganchapa!
54
+ - [#374](https://github.com/gradio-app/trackio/pull/374) [`388e26b`](https://github.com/gradio-app/trackio/commit/388e26b9e9f24cd7ad203affe9b709be885b3d24) - Save Optimized Parquet files. Thanks @lhoestq!
55
+ - [#371](https://github.com/gradio-app/trackio/pull/371) [`fbace9c`](https://github.com/gradio-app/trackio/commit/fbace9cd7732c166f34d268f54b05bb06846cc5d) - Add GPU metrics logging. Thanks @kashif!
56
+ - [#367](https://github.com/gradio-app/trackio/pull/367) [`862840c`](https://github.com/gradio-app/trackio/commit/862840c13e30fc960cbee5b9eac4d3c25beba9de) - Add option to only show latest run, and fix the double logo issue. Thanks @abidlabs!
57
+
58
+ ## 0.13.1
59
+
60
+ ### Features
61
+
62
+ - [#369](https://github.com/gradio-app/trackio/pull/369) [`767e9fe`](https://github.com/gradio-app/trackio/commit/767e9fe095d7c6ed102016caf927c1517fb8618c) - tiny pr removing unnecessary code. Thanks @abidlabs!
63
+
64
+ ## 0.13.0
65
+
66
+ ### Features
67
+
68
+ - [#358](https://github.com/gradio-app/trackio/pull/358) [`073715d`](https://github.com/gradio-app/trackio/commit/073715d1caf8282f68890117f09c3ac301205312) - Improvements to `trackio.sync()`. Thanks @abidlabs!
69
+
70
+ ## 0.12.0
71
+
72
+ ### Features
73
+
74
+ - [#357](https://github.com/gradio-app/trackio/pull/357) [`02ba815`](https://github.com/gradio-app/trackio/commit/02ba815358060f1966052de051a5bdb09702920e) - Redesign media and tables to show up on separate page. Thanks @abidlabs!
75
+ - [#359](https://github.com/gradio-app/trackio/pull/359) [`08fe9c9`](https://github.com/gradio-app/trackio/commit/08fe9c9ddd7fe99ee811555fdfb62df9ab88e939) - docs: Improve docstrings. Thanks @qgallouedec!
76
+
77
+ ## 0.11.0
78
+
79
+ ### Features
80
+
81
+ - [#355](https://github.com/gradio-app/trackio/pull/355) [`ea51f49`](https://github.com/gradio-app/trackio/commit/ea51f4954922f21be76ef828700420fe9a912c4b) - Color code run checkboxes and match with plot lines. Thanks @abidlabs!
82
+ - [#353](https://github.com/gradio-app/trackio/pull/353) [`8abe691`](https://github.com/gradio-app/trackio/commit/8abe6919aeefe21fc7a23af814883efbb037c21f) - Remove show_api from demo.launch. Thanks @sergiopaniego!
83
+ - [#351](https://github.com/gradio-app/trackio/pull/351) [`8a8957e`](https://github.com/gradio-app/trackio/commit/8a8957e530dd7908d1fef7f2df030303f808101f) - Add `trackio.save()`. Thanks @abidlabs!
84
+
85
+ ## 0.10.0
86
+
87
+ ### Features
88
+
89
+ - [#305](https://github.com/gradio-app/trackio/pull/305) [`e64883a`](https://github.com/gradio-app/trackio/commit/e64883a51f7b8b93f7d48b8afe55acdb62238b71) - bump to gradio 6.0, make `trackio` compatible, and fix related issues. Thanks @abidlabs!
90
+
91
+ ## 0.9.1
92
+
93
+ ### Features
94
+
95
+ - [#344](https://github.com/gradio-app/trackio/pull/344) [`7e01024`](https://github.com/gradio-app/trackio/commit/7e010241d9a34794e0ce0dc19c1a6f0cf94ba856) - Avoid redundant calls to /whoami-v2. Thanks @Wauplin!
96
+
97
+ ## 0.9.0
98
+
99
+ ### Features
100
+
101
+ - [#343](https://github.com/gradio-app/trackio/pull/343) [`51bea30`](https://github.com/gradio-app/trackio/commit/51bea30f2877adff8e6497466d3a799400a0a049) - Sync offline projects to Hugging Face spaces. Thanks @candemircan!
102
+ - [#341](https://github.com/gradio-app/trackio/pull/341) [`4fd841f`](https://github.com/gradio-app/trackio/commit/4fd841fa190e15071b02f6fba7683ef4f393a654) - Adds a basic UI test to `trackio`. Thanks @abidlabs!
103
+ - [#339](https://github.com/gradio-app/trackio/pull/339) [`011d91b`](https://github.com/gradio-app/trackio/commit/011d91bb6ae266516fd250a349285670a8049d05) - Allow customzing the trackio color palette. Thanks @abidlabs!
104
+
105
+ ## 0.8.1
106
+
107
+ ### Features
108
+
109
+ - [#336](https://github.com/gradio-app/trackio/pull/336) [`5f9f51d`](https://github.com/gradio-app/trackio/commit/5f9f51dac8677f240d7c42c3e3b2660a22aee138) - Support a list of `Trackio.Image` in a `trackio.Table` cell. Thanks @abidlabs!
110
+
111
+ ## 0.8.0
112
+
113
+ ### Features
114
+
115
+ - [#331](https://github.com/gradio-app/trackio/pull/331) [`2c02d0f`](https://github.com/gradio-app/trackio/commit/2c02d0fd0a5824160528782402bb0dd4083396d5) - Truncate table string values that are greater than 250 characters (configuirable via env variable). Thanks @abidlabs!
116
+ - [#324](https://github.com/gradio-app/trackio/pull/324) [`50b2122`](https://github.com/gradio-app/trackio/commit/50b2122e7965ac82a72e6cb3b7d048bc10a2a6b1) - Add log y-axis functionality to UI. Thanks @abidlabs!
117
+ - [#326](https://github.com/gradio-app/trackio/pull/326) [`61dc1f4`](https://github.com/gradio-app/trackio/commit/61dc1f40af2f545f8e70395ddf0dbb8aee6b60d5) - Fix: improve table rendering for metrics in Trackio Dashboard. Thanks @vigneshwaran!
118
+ - [#328](https://github.com/gradio-app/trackio/pull/328) [`6857cbb`](https://github.com/gradio-app/trackio/commit/6857cbbe557a59a4642f210ec42566d108294e63) - Support trackio.Table with trackio.Image columns. Thanks @abidlabs!
119
+ - [#323](https://github.com/gradio-app/trackio/pull/323) [`6857cbb`](https://github.com/gradio-app/trackio/commit/6857cbbe557a59a4642f210ec42566d108294e63) - add Trackio client implementations in Go, Rust, and JS. Thanks @vaibhav-research!
120
+
121
+ ## 0.7.0
122
+
123
+ ### Features
124
+
125
+ - [#277](https://github.com/gradio-app/trackio/pull/277) [`db35601`](https://github.com/gradio-app/trackio/commit/db35601b9c023423c4654c9909b8ab73e58737de) - fix: make grouped runs view reflect live updates. Thanks @Saba9!
126
+ - [#320](https://github.com/gradio-app/trackio/pull/320) [`24ae739`](https://github.com/gradio-app/trackio/commit/24ae73969b09fb3126acd2f91647cdfbf8cf72a1) - Add additional query parms for xmin, xmax, and smoothing. Thanks @abidlabs!
127
+ - [#270](https://github.com/gradio-app/trackio/pull/270) [`cd1dfc3`](https://github.com/gradio-app/trackio/commit/cd1dfc3dc641b4499ac6d4a1b066fa8e2b52c57b) - feature: add support for logging audio. Thanks @Saba9!
128
+
129
+ ## 0.6.0
130
+
131
+ ### Features
132
+
133
+ - [#309](https://github.com/gradio-app/trackio/pull/309) [`1df2353`](https://github.com/gradio-app/trackio/commit/1df23534d6c01938c8db9c0f584ffa23e8d6021d) - Add histogram support with wandb-compatible API. Thanks @abidlabs!
134
+ - [#315](https://github.com/gradio-app/trackio/pull/315) [`76ba060`](https://github.com/gradio-app/trackio/commit/76ba06055dc43ca8f03b79f3e72d761949bd19a8) - Add guards to avoid silent fails. Thanks @Xmaster6y!
135
+ - [#313](https://github.com/gradio-app/trackio/pull/313) [`a606b3e`](https://github.com/gradio-app/trackio/commit/a606b3e1c5edf3d4cf9f31bd50605226a5a1c5d0) - No longer prevent certain keys from being used. Instead, dunderify them to prevent collisions with internal usage. Thanks @abidlabs!
136
+ - [#317](https://github.com/gradio-app/trackio/pull/317) [`27370a5`](https://github.com/gradio-app/trackio/commit/27370a595d0dbdf7eebbe7159d2ba778f039da44) - quick fixes for trackio.histogram. Thanks @abidlabs!
137
+ - [#312](https://github.com/gradio-app/trackio/pull/312) [`aa0f3bf`](https://github.com/gradio-app/trackio/commit/aa0f3bf372e7a0dd592a38af699c998363830eeb) - Fix video logging by adding TRACKIO_DIR to allowed_paths. Thanks @abidlabs!
138
+
139
+ ## 0.5.3
140
+
141
+ ### Features
142
+
143
+ - [#300](https://github.com/gradio-app/trackio/pull/300) [`5e4cacf`](https://github.com/gradio-app/trackio/commit/5e4cacf2e7ce527b4ce60de3a5bc05d2c02c77fb) - Adds more environment variables to allow customization of Trackio dashboard. Thanks @abidlabs!
144
+
145
+ ## 0.5.2
146
+
147
+ ### Features
148
+
149
+ - [#293](https://github.com/gradio-app/trackio/pull/293) [`64afc28`](https://github.com/gradio-app/trackio/commit/64afc28d3ea1dfd821472dc6bf0b8ed35a9b74be) - Ensures that the TRACKIO_DIR environment variable is respected. Thanks @abidlabs!
150
+ - [#287](https://github.com/gradio-app/trackio/pull/287) [`cd3e929`](https://github.com/gradio-app/trackio/commit/cd3e9294320949e6b8b829239069a43d5d7ff4c1) - fix(sqlite): unify .sqlite extension, allow export when DBs exist, clean WAL sidecars on import. Thanks @vaibhav-research!
151
+
152
+ ### Fixes
153
+
154
+ - [#291](https://github.com/gradio-app/trackio/pull/291) [`3b5adc3`](https://github.com/gradio-app/trackio/commit/3b5adc3d1f452dbab7a714d235f4974782f93730) - Fix the wheel build. Thanks @pngwn!
155
+
156
+ ## 0.5.1
157
+
158
+ ### Fixes
159
+
160
+ - [#278](https://github.com/gradio-app/trackio/pull/278) [`314c054`](https://github.com/gradio-app/trackio/commit/314c05438007ddfea3383e06fd19143e27468e2d) - Fix row orientation of metrics plots. Thanks @abidlabs!
trackio/__init__.py ADDED
@@ -0,0 +1,664 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import atexit
2
+ import glob
3
+ import json
4
+ import logging
5
+ import os
6
+ import shutil
7
+ import warnings
8
+ import webbrowser
9
+ from pathlib import Path
10
+ from typing import Any
11
+
12
+ import huggingface_hub
13
+ from gradio.themes import ThemeClass
14
+ from gradio.utils import TupleNoPrint
15
+ from gradio_client import Client, handle_file
16
+ from huggingface_hub import SpaceStorage
17
+ from huggingface_hub.errors import LocalTokenNotFoundError
18
+
19
+ from trackio import context_vars, deploy, utils
20
+ from trackio.alerts import AlertLevel
21
+ from trackio.api import Api
22
+ from trackio.deploy import sync
23
+ from trackio.gpu import gpu_available, log_gpu
24
+ from trackio.histogram import Histogram
25
+ from trackio.imports import import_csv, import_tf_events
26
+ from trackio.markdown import Markdown
27
+ from trackio.media import (
28
+ TrackioAudio,
29
+ TrackioImage,
30
+ TrackioVideo,
31
+ get_project_media_path,
32
+ )
33
+ from trackio.run import Run
34
+ from trackio.sqlite_storage import SQLiteStorage
35
+ from trackio.table import Table
36
+ from trackio.typehints import UploadEntry
37
+ from trackio.utils import TRACKIO_DIR, TRACKIO_LOGO_DIR
38
+
39
+ logging.getLogger("httpx").setLevel(logging.WARNING)
40
+
41
+ warnings.filterwarnings(
42
+ "ignore",
43
+ message="Empty session being created. Install gradio\\[oauth\\]",
44
+ category=UserWarning,
45
+ module="gradio.helpers",
46
+ )
47
+
48
+ __version__ = json.loads(Path(__file__).parent.joinpath("package.json").read_text())[
49
+ "version"
50
+ ]
51
+
52
+ __all__ = [
53
+ "init",
54
+ "log",
55
+ "log_system",
56
+ "log_gpu",
57
+ "finish",
58
+ "alert",
59
+ "AlertLevel",
60
+ "show",
61
+ "sync",
62
+ "delete_project",
63
+ "import_csv",
64
+ "import_tf_events",
65
+ "save",
66
+ "Image",
67
+ "Video",
68
+ "Audio",
69
+ "Table",
70
+ "Histogram",
71
+ "Markdown",
72
+ "Api",
73
+ ]
74
+
75
+ Image = TrackioImage
76
+ Video = TrackioVideo
77
+ Audio = TrackioAudio
78
+
79
+
80
+ config = {}
81
+
82
+ _atexit_registered = False
83
+
84
+
85
+ def _cleanup_current_run():
86
+ run = context_vars.current_run.get()
87
+ if run is not None:
88
+ try:
89
+ run.finish()
90
+ except Exception:
91
+ pass
92
+
93
+
94
+ def _get_demo():
95
+ # Lazy import to avoid initializing Gradio Blocks (and FastAPI) at import time,
96
+ # which causes import lock errors for libraries that just `import trackio`.
97
+ from trackio.ui.main import CSS, HEAD, demo
98
+
99
+ return demo, CSS, HEAD
100
+
101
+
102
+ def init(
103
+ project: str,
104
+ name: str | None = None,
105
+ group: str | None = None,
106
+ space_id: str | None = None,
107
+ space_storage: SpaceStorage | None = None,
108
+ dataset_id: str | None = None,
109
+ config: dict | None = None,
110
+ resume: str = "never",
111
+ settings: Any = None,
112
+ private: bool | None = None,
113
+ embed: bool = True,
114
+ auto_log_gpu: bool | None = None,
115
+ gpu_log_interval: float = 10.0,
116
+ webhook_url: str | None = None,
117
+ webhook_min_level: AlertLevel | str | None = None,
118
+ ) -> Run:
119
+ """
120
+ Creates a new Trackio project and returns a [`Run`] object.
121
+
122
+ Args:
123
+ project (`str`):
124
+ The name of the project (can be an existing project to continue tracking or
125
+ a new project to start tracking from scratch).
126
+ name (`str`, *optional*):
127
+ The name of the run (if not provided, a default name will be generated).
128
+ group (`str`, *optional*):
129
+ The name of the group which this run belongs to in order to help organize
130
+ related runs together. You can toggle the entire group's visibilitiy in the
131
+ dashboard.
132
+ space_id (`str`, *optional*):
133
+ If provided, the project will be logged to a Hugging Face Space instead of
134
+ a local directory. Should be a complete Space name like
135
+ `"username/reponame"` or `"orgname/reponame"`, or just `"reponame"` in which
136
+ case the Space will be created in the currently-logged-in Hugging Face
137
+ user's namespace. If the Space does not exist, it will be created. If the
138
+ Space already exists, the project will be logged to it.
139
+ space_storage ([`~huggingface_hub.SpaceStorage`], *optional*):
140
+ Choice of persistent storage tier.
141
+ dataset_id (`str`, *optional*):
142
+ If a `space_id` is provided, a persistent Hugging Face Dataset will be
143
+ created and the metrics will be synced to it every 5 minutes. Specify a
144
+ Dataset with name like `"username/datasetname"` or `"orgname/datasetname"`,
145
+ or `"datasetname"` (uses currently-logged-in Hugging Face user's namespace),
146
+ or `None` (uses the same name as the Space but with the `"_dataset"`
147
+ suffix). If the Dataset does not exist, it will be created. If the Dataset
148
+ already exists, the project will be appended to it.
149
+ config (`dict`, *optional*):
150
+ A dictionary of configuration options. Provided for compatibility with
151
+ `wandb.init()`.
152
+ resume (`str`, *optional*, defaults to `"never"`):
153
+ Controls how to handle resuming a run. Can be one of:
154
+
155
+ - `"must"`: Must resume the run with the given name, raises error if run
156
+ doesn't exist
157
+ - `"allow"`: Resume the run if it exists, otherwise create a new run
158
+ - `"never"`: Never resume a run, always create a new one
159
+ private (`bool`, *optional*):
160
+ Whether to make the Space private. If None (default), the repo will be
161
+ public unless the organization's default is private. This value is ignored
162
+ if the repo already exists.
163
+ settings (`Any`, *optional*):
164
+ Not used. Provided for compatibility with `wandb.init()`.
165
+ embed (`bool`, *optional*, defaults to `True`):
166
+ If running inside a Jupyter/Colab notebook, whether the dashboard should
167
+ automatically be embedded in the cell when trackio.init() is called. For
168
+ local runs, this launches a local Gradio app and embeds it. For Space runs,
169
+ this embeds the Space URL. In Colab, the local dashboard will be accessible
170
+ via a public share URL (default Gradio behavior).
171
+ auto_log_gpu (`bool` or `None`, *optional*, defaults to `None`):
172
+ Controls automatic GPU metrics logging. If `None` (default), GPU logging
173
+ is automatically enabled when `nvidia-ml-py` is installed and an NVIDIA
174
+ GPU is detected. Set to `True` to force enable or `False` to disable.
175
+ gpu_log_interval (`float`, *optional*, defaults to `10.0`):
176
+ The interval in seconds between automatic GPU metric logs.
177
+ Only used when `auto_log_gpu=True`.
178
+ webhook_url (`str`, *optional*):
179
+ A webhook URL to POST alert payloads to when `trackio.alert()` is
180
+ called. Supports Slack and Discord webhook URLs natively (payloads
181
+ are formatted automatically). Can also be set via the
182
+ `TRACKIO_WEBHOOK_URL` environment variable. Individual alerts can
183
+ override this URL by passing `webhook_url` to `trackio.alert()`.
184
+ webhook_min_level (`AlertLevel` or `str`, *optional*):
185
+ Minimum alert level that should trigger webhook delivery.
186
+ For example, `AlertLevel.WARN` sends only `WARN` and `ERROR`
187
+ alerts to the webhook destination. Can also be set via
188
+ `TRACKIO_WEBHOOK_MIN_LEVEL`.
189
+ Returns:
190
+ `Run`: A [`Run`] object that can be used to log metrics and finish the run.
191
+ """
192
+ if settings is not None:
193
+ warnings.warn(
194
+ "* Warning: settings is not used. Provided for compatibility with wandb.init(). Please create an issue at: https://github.com/gradio-app/trackio/issues if you need a specific feature implemented."
195
+ )
196
+
197
+ if space_id is None and dataset_id is not None:
198
+ raise ValueError("Must provide a `space_id` when `dataset_id` is provided.")
199
+ try:
200
+ space_id, dataset_id = utils.preprocess_space_and_dataset_ids(
201
+ space_id, dataset_id
202
+ )
203
+ except LocalTokenNotFoundError as e:
204
+ raise LocalTokenNotFoundError(
205
+ f"You must be logged in to Hugging Face locally when `space_id` is provided to deploy to a Space. {e}"
206
+ ) from e
207
+
208
+ url = context_vars.current_server.get()
209
+
210
+ if space_id is not None:
211
+ if url is None:
212
+ url = space_id
213
+ context_vars.current_server.set(url)
214
+ context_vars.current_space_id.set(space_id)
215
+
216
+ _should_embed_local = False
217
+
218
+ if (
219
+ context_vars.current_project.get() is None
220
+ or context_vars.current_project.get() != project
221
+ ):
222
+ print(f"* Trackio project initialized: {project}")
223
+
224
+ if dataset_id is not None:
225
+ os.environ["TRACKIO_DATASET_ID"] = dataset_id
226
+ print(
227
+ f"* Trackio metrics will be synced to Hugging Face Dataset: {dataset_id}"
228
+ )
229
+ if space_id is None:
230
+ print(f"* Trackio metrics logged to: {TRACKIO_DIR}")
231
+ _should_embed_local = embed and utils.is_in_notebook()
232
+ if not _should_embed_local:
233
+ utils.print_dashboard_instructions(project)
234
+ else:
235
+ deploy.create_space_if_not_exists(
236
+ space_id, space_storage, dataset_id, private
237
+ )
238
+ user_name, space_name = space_id.split("/")
239
+ space_url = deploy.SPACE_HOST_URL.format(
240
+ user_name=user_name, space_name=space_name
241
+ )
242
+ print(f"* View dashboard by going to: {space_url}")
243
+ if utils.is_in_notebook() and embed:
244
+ utils.embed_url_in_notebook(space_url)
245
+ context_vars.current_project.set(project)
246
+
247
+ if resume == "must":
248
+ if name is None:
249
+ raise ValueError("Must provide a run name when resume='must'")
250
+ if name not in SQLiteStorage.get_runs(project):
251
+ raise ValueError(f"Run '{name}' does not exist in project '{project}'")
252
+ resumed = True
253
+ elif resume == "allow":
254
+ resumed = name is not None and name in SQLiteStorage.get_runs(project)
255
+ elif resume == "never":
256
+ if name is not None and name in SQLiteStorage.get_runs(project):
257
+ warnings.warn(
258
+ f"* Warning: resume='never' but a run '{name}' already exists in "
259
+ f"project '{project}'. Generating a new name and instead. If you want "
260
+ "to resume this run, call init() with resume='must' or resume='allow'."
261
+ )
262
+ name = None
263
+ resumed = False
264
+ else:
265
+ raise ValueError("resume must be one of: 'must', 'allow', or 'never'")
266
+
267
+ if auto_log_gpu is None:
268
+ auto_log_gpu = gpu_available()
269
+ if auto_log_gpu:
270
+ print("* GPU detected, enabling automatic GPU metrics logging")
271
+
272
+ run = Run(
273
+ url=url,
274
+ project=project,
275
+ client=None,
276
+ name=name,
277
+ group=group,
278
+ config=config,
279
+ space_id=space_id,
280
+ auto_log_gpu=auto_log_gpu,
281
+ gpu_log_interval=gpu_log_interval,
282
+ webhook_url=webhook_url,
283
+ webhook_min_level=webhook_min_level,
284
+ )
285
+
286
+ if space_id is not None:
287
+ SQLiteStorage.set_project_metadata(project, "space_id", space_id)
288
+ if SQLiteStorage.has_pending_data(project):
289
+ run._has_local_buffer = True
290
+
291
+ global _atexit_registered
292
+ if not _atexit_registered:
293
+ atexit.register(_cleanup_current_run)
294
+ _atexit_registered = True
295
+
296
+ if resumed:
297
+ print(f"* Resumed existing run: {run.name}")
298
+ else:
299
+ print(f"* Created new run: {run.name}")
300
+
301
+ context_vars.current_run.set(run)
302
+ globals()["config"] = run.config
303
+
304
+ if _should_embed_local:
305
+ show(project=project, open_browser=False, block_thread=False)
306
+
307
+ return run
308
+
309
+
310
+ def log(metrics: dict, step: int | None = None) -> None:
311
+ """
312
+ Logs metrics to the current run.
313
+
314
+ Args:
315
+ metrics (`dict`):
316
+ A dictionary of metrics to log.
317
+ step (`int`, *optional*):
318
+ The step number. If not provided, the step will be incremented
319
+ automatically.
320
+ """
321
+ run = context_vars.current_run.get()
322
+ if run is None:
323
+ raise RuntimeError("Call trackio.init() before trackio.log().")
324
+ run.log(
325
+ metrics=metrics,
326
+ step=step,
327
+ )
328
+
329
+
330
+ def log_system(metrics: dict) -> None:
331
+ """
332
+ Logs system metrics (GPU, etc.) to the current run using timestamps instead of steps.
333
+
334
+ Args:
335
+ metrics (`dict`):
336
+ A dictionary of system metrics to log.
337
+ """
338
+ run = context_vars.current_run.get()
339
+ if run is None:
340
+ raise RuntimeError("Call trackio.init() before trackio.log_system().")
341
+ run.log_system(metrics=metrics)
342
+
343
+
344
+ def finish():
345
+ """
346
+ Finishes the current run.
347
+ """
348
+ run = context_vars.current_run.get()
349
+ if run is None:
350
+ raise RuntimeError("Call trackio.init() before trackio.finish().")
351
+ run.finish()
352
+
353
+
354
+ def alert(
355
+ title: str,
356
+ text: str | None = None,
357
+ level: AlertLevel = AlertLevel.WARN,
358
+ webhook_url: str | None = None,
359
+ ) -> None:
360
+ """
361
+ Fires an alert immediately on the current run. The alert is printed to the
362
+ terminal, stored in the database, and displayed in the dashboard. If a
363
+ webhook URL is configured (via `trackio.init()`, the `TRACKIO_WEBHOOK_URL`
364
+ environment variable, or the `webhook_url` parameter here), the alert is
365
+ also POSTed to that URL.
366
+
367
+ Args:
368
+ title (`str`):
369
+ A short title for the alert.
370
+ text (`str`, *optional*):
371
+ A longer description with details about the alert.
372
+ level (`AlertLevel`, *optional*, defaults to `AlertLevel.WARN`):
373
+ The severity level. One of `AlertLevel.INFO`, `AlertLevel.WARN`,
374
+ or `AlertLevel.ERROR`.
375
+ webhook_url (`str`, *optional*):
376
+ A webhook URL to send this specific alert to. Overrides any
377
+ URL set in `trackio.init()` or the `TRACKIO_WEBHOOK_URL`
378
+ environment variable. Supports Slack and Discord webhook
379
+ URLs natively.
380
+ """
381
+ run = context_vars.current_run.get()
382
+ if run is None:
383
+ raise RuntimeError("Call trackio.init() before trackio.alert().")
384
+ run.alert(title=title, text=text, level=level, webhook_url=webhook_url)
385
+
386
+
387
+ def delete_project(project: str, force: bool = False) -> bool:
388
+ """
389
+ Deletes a project by removing its local SQLite database.
390
+
391
+ Args:
392
+ project (`str`):
393
+ The name of the project to delete.
394
+ force (`bool`, *optional*, defaults to `False`):
395
+ If `True`, deletes the project without prompting for confirmation.
396
+ If `False`, prompts the user to confirm before deleting.
397
+
398
+ Returns:
399
+ `bool`: `True` if the project was deleted, `False` otherwise.
400
+ """
401
+ db_path = SQLiteStorage.get_project_db_path(project)
402
+
403
+ if not db_path.exists():
404
+ print(f"* Project '{project}' does not exist.")
405
+ return False
406
+
407
+ if not force:
408
+ response = input(
409
+ f"Are you sure you want to delete project '{project}'? "
410
+ f"This will permanently delete all runs and metrics. (y/N): "
411
+ )
412
+ if response.lower() not in ["y", "yes"]:
413
+ print("* Deletion cancelled.")
414
+ return False
415
+
416
+ try:
417
+ db_path.unlink()
418
+
419
+ for suffix in ("-wal", "-shm"):
420
+ sidecar = Path(str(db_path) + suffix)
421
+ if sidecar.exists():
422
+ sidecar.unlink()
423
+
424
+ print(f"* Project '{project}' has been deleted.")
425
+ return True
426
+ except Exception as e:
427
+ print(f"* Error deleting project '{project}': {e}")
428
+ return False
429
+
430
+
431
+ def save(
432
+ glob_str: str | Path,
433
+ project: str | None = None,
434
+ ) -> str:
435
+ """
436
+ Saves files to a project (not linked to a specific run). If Trackio is running
437
+ locally, the file(s) will be copied to the project's files directory. If Trackio is
438
+ running in a Space, the file(s) will be uploaded to the Space's files directory.
439
+
440
+ Args:
441
+ glob_str (`str` or `Path`):
442
+ The file path or glob pattern to save. Can be a single file or a pattern
443
+ matching multiple files (e.g., `"*.py"`, `"models/**/*.pth"`).
444
+ project (`str`, *optional*):
445
+ The name of the project to save files to. If not provided, uses the current
446
+ project from `trackio.init()`. If no project is initialized, raises an
447
+ error.
448
+
449
+ Returns:
450
+ `str`: The path where the file(s) were saved (project's files directory).
451
+
452
+ Example:
453
+ ```python
454
+ import trackio
455
+
456
+ trackio.init(project="my-project")
457
+ trackio.save("config.yaml")
458
+ trackio.save("models/*.pth")
459
+ ```
460
+ """
461
+ if project is None:
462
+ project = context_vars.current_project.get()
463
+ if project is None:
464
+ raise RuntimeError(
465
+ "No project specified. Either call trackio.init() first or provide a "
466
+ "project parameter to trackio.save()."
467
+ )
468
+
469
+ glob_str = Path(glob_str)
470
+ base_path = Path.cwd().resolve()
471
+
472
+ matched_files = []
473
+ if glob_str.is_file():
474
+ matched_files = [glob_str.resolve()]
475
+ else:
476
+ pattern = str(glob_str)
477
+ if not glob_str.is_absolute():
478
+ pattern = str((Path.cwd() / glob_str).resolve())
479
+ matched_files = [
480
+ Path(f).resolve()
481
+ for f in glob.glob(pattern, recursive=True)
482
+ if Path(f).is_file()
483
+ ]
484
+
485
+ if not matched_files:
486
+ raise ValueError(f"No files found matching pattern: {glob_str}")
487
+
488
+ current_run = context_vars.current_run.get()
489
+ is_local = (
490
+ current_run._is_local
491
+ if current_run is not None
492
+ else (context_vars.current_space_id.get() is None)
493
+ )
494
+
495
+ if is_local:
496
+ for file_path in matched_files:
497
+ try:
498
+ relative_to_base = file_path.relative_to(base_path)
499
+ except ValueError:
500
+ relative_to_base = Path(file_path.name)
501
+
502
+ if current_run is not None:
503
+ current_run._queue_upload(
504
+ file_path,
505
+ step=None,
506
+ relative_path=str(relative_to_base.parent),
507
+ use_run_name=False,
508
+ )
509
+ else:
510
+ media_path = get_project_media_path(
511
+ project=project,
512
+ run=None,
513
+ step=None,
514
+ relative_path=str(relative_to_base),
515
+ )
516
+ shutil.copy(str(file_path), str(media_path))
517
+ else:
518
+ url = context_vars.current_server.get()
519
+
520
+ upload_entries = []
521
+ for file_path in matched_files:
522
+ try:
523
+ relative_to_base = file_path.relative_to(base_path)
524
+ except ValueError:
525
+ relative_to_base = Path(file_path.name)
526
+
527
+ if current_run is not None:
528
+ current_run._queue_upload(
529
+ file_path,
530
+ step=None,
531
+ relative_path=str(relative_to_base.parent),
532
+ use_run_name=False,
533
+ )
534
+ else:
535
+ upload_entry: UploadEntry = {
536
+ "project": project,
537
+ "run": None,
538
+ "step": None,
539
+ "relative_path": str(relative_to_base),
540
+ "uploaded_file": handle_file(file_path),
541
+ }
542
+ upload_entries.append(upload_entry)
543
+
544
+ if upload_entries:
545
+ if url is None:
546
+ raise RuntimeError(
547
+ "No server available. Call trackio.init() before trackio.save() to start the server."
548
+ )
549
+
550
+ try:
551
+ client = Client(url, verbose=False, httpx_kwargs={"timeout": 90})
552
+ client.predict(
553
+ api_name="/bulk_upload_media",
554
+ uploads=upload_entries,
555
+ hf_token=huggingface_hub.utils.get_token(),
556
+ )
557
+ except Exception as e:
558
+ warnings.warn(
559
+ f"Failed to upload files: {e}. "
560
+ "Files may not be available in the dashboard."
561
+ )
562
+
563
+ return str(utils.MEDIA_DIR / project / "files")
564
+
565
+
566
+ def show(
567
+ project: str | None = None,
568
+ *,
569
+ theme: str | ThemeClass | None = None,
570
+ mcp_server: bool | None = None,
571
+ footer: bool = True,
572
+ color_palette: list[str] | None = None,
573
+ open_browser: bool = True,
574
+ block_thread: bool | None = None,
575
+ host: str | None = None,
576
+ ):
577
+ """
578
+ Launches the Trackio dashboard.
579
+
580
+ Args:
581
+ project (`str`, *optional*):
582
+ The name of the project whose runs to show. If not provided, all projects
583
+ will be shown and the user can select one.
584
+ theme (`str` or `ThemeClass`, *optional*):
585
+ A Gradio Theme to use for the dashboard instead of the default Gradio theme,
586
+ can be a built-in theme (e.g. `'soft'`, `'citrus'`), a theme from the Hub
587
+ (e.g. `"gstaff/xkcd"`), or a custom Theme class. If not provided, the
588
+ `TRACKIO_THEME` environment variable will be used, or if that is not set,
589
+ the default Gradio theme will be used.
590
+ mcp_server (`bool`, *optional*):
591
+ If `True`, the Trackio dashboard will be set up as an MCP server and certain
592
+ functions will be added as MCP tools. If `None` (default behavior), then the
593
+ `GRADIO_MCP_SERVER` environment variable will be used to determine if the
594
+ MCP server should be enabled (which is `"True"` on Hugging Face Spaces).
595
+ footer (`bool`, *optional*, defaults to `True`):
596
+ Whether to show the Gradio footer. When `False`, the footer will be hidden.
597
+ This can also be controlled via the `footer` query parameter in the URL.
598
+ color_palette (`list[str]`, *optional*):
599
+ A list of hex color codes to use for plot lines. If not provided, the
600
+ `TRACKIO_COLOR_PALETTE` environment variable will be used (comma-separated
601
+ hex codes), or if that is not set, the default color palette will be used.
602
+ Example: `['#FF0000', '#00FF00', '#0000FF']`
603
+ open_browser (`bool`, *optional*, defaults to `True`):
604
+ If `True` and not in a notebook, a new browser tab will be opened with the
605
+ dashboard. If `False`, the browser will not be opened.
606
+ block_thread (`bool`, *optional*):
607
+ If `True`, the main thread will be blocked until the dashboard is closed.
608
+ If `None` (default behavior), then the main thread will not be blocked if the
609
+ dashboard is launched in a notebook, otherwise the main thread will be blocked.
610
+ host (`str`, *optional*):
611
+ The host to bind the server to. If not provided, defaults to `'127.0.0.1'`
612
+ (localhost only). Set to `'0.0.0.0'` to allow remote access.
613
+
614
+ Returns:
615
+ `app`: The Gradio app object corresponding to the dashboard launched by Trackio.
616
+ `url`: The local URL of the dashboard.
617
+ `share_url`: The public share URL of the dashboard.
618
+ `full_url`: The full URL of the dashboard including the write token (will use the public share URL if launched publicly, otherwise the local URL).
619
+ """
620
+ demo, CSS, HEAD = _get_demo()
621
+
622
+ if color_palette is not None:
623
+ os.environ["TRACKIO_COLOR_PALETTE"] = ",".join(color_palette)
624
+
625
+ theme = theme or os.environ.get("TRACKIO_THEME")
626
+
627
+ _mcp_server = (
628
+ mcp_server
629
+ if mcp_server is not None
630
+ else os.environ.get("GRADIO_MCP_SERVER", "False") == "True"
631
+ )
632
+
633
+ app, url, share_url = demo.launch(
634
+ css=CSS,
635
+ head=HEAD,
636
+ footer_links=["gradio", "settings"] + (["api"] if _mcp_server else []),
637
+ quiet=True,
638
+ inline=False,
639
+ prevent_thread_lock=True,
640
+ favicon_path=TRACKIO_LOGO_DIR / "trackio_logo_light.png",
641
+ allowed_paths=[TRACKIO_LOGO_DIR, TRACKIO_DIR],
642
+ mcp_server=_mcp_server,
643
+ theme=theme,
644
+ ssr_mode=False,
645
+ server_name=host,
646
+ )
647
+
648
+ base_url = share_url + "/" if share_url else url
649
+ full_url = utils.get_full_url(
650
+ base_url, project=project, write_token=demo.write_token, footer=footer
651
+ )
652
+
653
+ if not utils.is_in_notebook():
654
+ print(f"* Trackio UI launched at: {full_url}")
655
+ if open_browser:
656
+ webbrowser.open(full_url)
657
+ block_thread = block_thread if block_thread is not None else True
658
+ else:
659
+ utils.embed_url_in_notebook(full_url)
660
+ block_thread = block_thread if block_thread is not None else False
661
+
662
+ if block_thread:
663
+ utils.block_main_thread_until_keyboard_interrupt()
664
+ return TupleNoPrint((demo, url, share_url, full_url))
trackio/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (23.7 kB). View file
 
trackio/__pycache__/__init__.cpython-313.pyc ADDED
Binary file (27.1 kB). View file
 
trackio/__pycache__/alerts.cpython-313.pyc ADDED
Binary file (7.51 kB). View file
 
trackio/__pycache__/api.cpython-312.pyc ADDED
Binary file (4.42 kB). View file
 
trackio/__pycache__/api.cpython-313.pyc ADDED
Binary file (5.86 kB). View file
 
trackio/__pycache__/cli.cpython-312.pyc ADDED
Binary file (1.71 kB). View file
 
trackio/__pycache__/cli.cpython-313.pyc ADDED
Binary file (23.3 kB). View file
 
trackio/__pycache__/cli_helpers.cpython-313.pyc ADDED
Binary file (6.04 kB). View file
 
trackio/__pycache__/commit_scheduler.cpython-312.pyc ADDED
Binary file (18.8 kB). View file
 
trackio/__pycache__/commit_scheduler.cpython-313.pyc ADDED
Binary file (14.1 kB). View file
 
trackio/__pycache__/context_vars.cpython-312.pyc ADDED
Binary file (1.07 kB). View file
 
trackio/__pycache__/context_vars.cpython-313.pyc ADDED
Binary file (892 Bytes). View file
 
trackio/__pycache__/deploy.cpython-312.pyc ADDED
Binary file (14.8 kB). View file
 
trackio/__pycache__/deploy.cpython-313.pyc ADDED
Binary file (18.8 kB). View file
 
trackio/__pycache__/dummy_commit_scheduler.cpython-312.pyc ADDED
Binary file (1.01 kB). View file
 
trackio/__pycache__/dummy_commit_scheduler.cpython-313.pyc ADDED
Binary file (1.1 kB). View file
 
trackio/__pycache__/file_storage.cpython-312.pyc ADDED
Binary file (1.63 kB). View file
 
trackio/__pycache__/gpu.cpython-312.pyc ADDED
Binary file (14.7 kB). View file
 
trackio/__pycache__/gpu.cpython-313.pyc ADDED
Binary file (14.3 kB). View file
 
trackio/__pycache__/histogram.cpython-312.pyc ADDED
Binary file (3.23 kB). View file
 
trackio/__pycache__/histogram.cpython-313.pyc ADDED
Binary file (3.22 kB). View file
 
trackio/__pycache__/imports.cpython-312.pyc ADDED
Binary file (13.3 kB). View file
 
trackio/__pycache__/imports.cpython-313.pyc ADDED
Binary file (13.2 kB). View file
 
trackio/__pycache__/markdown.cpython-313.pyc ADDED
Binary file (1.09 kB). View file
 
trackio/__pycache__/media.cpython-312.pyc ADDED
Binary file (14.1 kB). View file
 
trackio/__pycache__/run.cpython-312.pyc ADDED
Binary file (14.7 kB). View file
 
trackio/__pycache__/run.cpython-313.pyc ADDED
Binary file (33.6 kB). View file
 
trackio/__pycache__/sqlite_storage.cpython-312.pyc ADDED
Binary file (49.4 kB). View file
 
trackio/__pycache__/sqlite_storage.cpython-313.pyc ADDED
Binary file (79.1 kB). View file
 
trackio/__pycache__/table.cpython-312.pyc ADDED
Binary file (8.59 kB). View file
 
trackio/__pycache__/table.cpython-313.pyc ADDED
Binary file (8.51 kB). View file
 
trackio/__pycache__/typehints.cpython-312.pyc ADDED
Binary file (1.24 kB). View file
 
trackio/__pycache__/typehints.cpython-313.pyc ADDED
Binary file (1.83 kB). View file
 
trackio/__pycache__/ui.cpython-312.pyc ADDED
Binary file (32.6 kB). View file
 
trackio/__pycache__/utils.cpython-312.pyc ADDED
Binary file (29.8 kB). View file
 
trackio/__pycache__/utils.cpython-313.pyc ADDED
Binary file (30.1 kB). View file
 
trackio/__pycache__/video_writer.cpython-312.pyc ADDED
Binary file (5.32 kB). View file
 
trackio/alerts.py ADDED
@@ -0,0 +1,185 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import logging
3
+ import ssl
4
+ import urllib.error
5
+ import urllib.request
6
+ from enum import Enum
7
+
8
+ try:
9
+ import certifi
10
+
11
+ _SSL_CONTEXT = ssl.create_default_context(cafile=certifi.where())
12
+ except ImportError:
13
+ _SSL_CONTEXT = None
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ class AlertLevel(str, Enum):
19
+ INFO = "info"
20
+ WARN = "warn"
21
+ ERROR = "error"
22
+
23
+
24
+ ALERT_LEVEL_ORDER = {
25
+ AlertLevel.INFO: 0,
26
+ AlertLevel.WARN: 1,
27
+ AlertLevel.ERROR: 2,
28
+ }
29
+
30
+ ALERT_COLORS = {
31
+ AlertLevel.INFO: "\033[94m",
32
+ AlertLevel.WARN: "\033[93m",
33
+ AlertLevel.ERROR: "\033[91m",
34
+ }
35
+ RESET_COLOR = "\033[0m"
36
+
37
+ LEVEL_EMOJI = {
38
+ AlertLevel.INFO: "ℹ️",
39
+ AlertLevel.WARN: "⚠️",
40
+ AlertLevel.ERROR: "🚨",
41
+ }
42
+
43
+
44
+ def format_alert_terminal(
45
+ level: AlertLevel, title: str, text: str | None, step: int | None
46
+ ) -> str:
47
+ color = ALERT_COLORS.get(level, "")
48
+ step_str = f" (step {step})" if step is not None else ""
49
+ if text:
50
+ return f"{color}[TRACKIO {level.value.upper()}]{RESET_COLOR} {title}: {text}{step_str}"
51
+ return f"{color}[TRACKIO {level.value.upper()}]{RESET_COLOR} {title}{step_str}"
52
+
53
+
54
+ def _is_slack_url(url: str) -> bool:
55
+ return "hooks.slack.com" in url
56
+
57
+
58
+ def _is_discord_url(url: str) -> bool:
59
+ return "discord.com/api/webhooks" in url or "discordapp.com/api/webhooks" in url
60
+
61
+
62
+ def _build_slack_payload(
63
+ level: AlertLevel,
64
+ title: str,
65
+ text: str | None,
66
+ project: str,
67
+ run: str,
68
+ step: int | None,
69
+ ) -> dict:
70
+ emoji = LEVEL_EMOJI.get(level, "")
71
+ step_str = f" • Step {step}" if step is not None else ""
72
+ header = f"{emoji} *[{level.value.upper()}] {title}*"
73
+ context = f"Project: {project} • Run: {run}{step_str}"
74
+ blocks = [
75
+ {"type": "section", "text": {"type": "mrkdwn", "text": header}},
76
+ ]
77
+ if text:
78
+ blocks.append({"type": "section", "text": {"type": "mrkdwn", "text": text}})
79
+ blocks.append(
80
+ {"type": "context", "elements": [{"type": "mrkdwn", "text": context}]}
81
+ )
82
+ return {"blocks": blocks}
83
+
84
+
85
+ def _build_discord_payload(
86
+ level: AlertLevel,
87
+ title: str,
88
+ text: str | None,
89
+ project: str,
90
+ run: str,
91
+ step: int | None,
92
+ ) -> dict:
93
+ color_map = {
94
+ AlertLevel.INFO: 3447003,
95
+ AlertLevel.WARN: 16776960,
96
+ AlertLevel.ERROR: 15158332,
97
+ }
98
+ emoji = LEVEL_EMOJI.get(level, "")
99
+ step_str = f" • Step {step}" if step is not None else ""
100
+ embed = {
101
+ "title": f"{emoji} [{level.value.upper()}] {title}",
102
+ "color": color_map.get(level, 0),
103
+ "footer": {"text": f"Project: {project} • Run: {run}{step_str}"},
104
+ }
105
+ if text:
106
+ embed["description"] = text
107
+ return {"embeds": [embed]}
108
+
109
+
110
+ def _build_generic_payload(
111
+ level: AlertLevel,
112
+ title: str,
113
+ text: str | None,
114
+ project: str,
115
+ run: str,
116
+ step: int | None,
117
+ timestamp: str | None,
118
+ ) -> dict:
119
+ return {
120
+ "level": level.value,
121
+ "title": title,
122
+ "text": text,
123
+ "project": project,
124
+ "run": run,
125
+ "step": step,
126
+ "timestamp": timestamp,
127
+ }
128
+
129
+
130
+ def parse_alert_level(level: AlertLevel | str) -> AlertLevel:
131
+ if isinstance(level, AlertLevel):
132
+ return level
133
+ normalized = level.lower().strip()
134
+ try:
135
+ return AlertLevel(normalized)
136
+ except ValueError as e:
137
+ allowed = ", ".join(lvl.value for lvl in AlertLevel)
138
+ raise ValueError(
139
+ f"Invalid alert level '{level}'. Expected one of: {allowed}."
140
+ ) from e
141
+
142
+
143
+ def resolve_webhook_min_level(
144
+ webhook_min_level: AlertLevel | str | None,
145
+ ) -> AlertLevel | None:
146
+ if webhook_min_level is None:
147
+ return None
148
+ return parse_alert_level(webhook_min_level)
149
+
150
+
151
+ def should_send_webhook(
152
+ level: AlertLevel, webhook_min_level: AlertLevel | None
153
+ ) -> bool:
154
+ if webhook_min_level is None:
155
+ return True
156
+ return ALERT_LEVEL_ORDER[level] >= ALERT_LEVEL_ORDER[webhook_min_level]
157
+
158
+
159
+ def send_webhook(
160
+ url: str,
161
+ level: AlertLevel,
162
+ title: str,
163
+ text: str | None,
164
+ project: str,
165
+ run: str,
166
+ step: int | None,
167
+ timestamp: str | None = None,
168
+ ) -> None:
169
+ if _is_slack_url(url):
170
+ payload = _build_slack_payload(level, title, text, project, run, step)
171
+ elif _is_discord_url(url):
172
+ payload = _build_discord_payload(level, title, text, project, run, step)
173
+ else:
174
+ payload = _build_generic_payload(
175
+ level, title, text, project, run, step, timestamp
176
+ )
177
+
178
+ data = json.dumps(payload).encode("utf-8")
179
+ req = urllib.request.Request(
180
+ url, data=data, headers={"Content-Type": "application/json"}
181
+ )
182
+ try:
183
+ urllib.request.urlopen(req, timeout=10, context=_SSL_CONTEXT)
184
+ except Exception as e:
185
+ logger.warning(f"Failed to send webhook to {url}: {e}")
trackio/api.py ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Iterator
2
+
3
+ from trackio.sqlite_storage import SQLiteStorage
4
+
5
+
6
+ class Run:
7
+ def __init__(self, project: str, name: str):
8
+ self.project = project
9
+ self.name = name
10
+ self._config = None
11
+
12
+ @property
13
+ def id(self) -> str:
14
+ return self.name
15
+
16
+ @property
17
+ def config(self) -> dict | None:
18
+ if self._config is None:
19
+ self._config = SQLiteStorage.get_run_config(self.project, self.name)
20
+ return self._config
21
+
22
+ def alerts(self, level: str | None = None, since: str | None = None) -> list[dict]:
23
+ return SQLiteStorage.get_alerts(
24
+ self.project, run_name=self.name, level=level, since=since
25
+ )
26
+
27
+ def delete(self) -> bool:
28
+ return SQLiteStorage.delete_run(self.project, self.name)
29
+
30
+ def move(self, new_project: str) -> bool:
31
+ success = SQLiteStorage.move_run(self.project, self.name, new_project)
32
+ if success:
33
+ self.project = new_project
34
+ return success
35
+
36
+ def rename(self, new_name: str) -> "Run":
37
+ SQLiteStorage.rename_run(self.project, self.name, new_name)
38
+ self.name = new_name
39
+ return self
40
+
41
+ def __repr__(self) -> str:
42
+ return f"<Run {self.name} in project {self.project}>"
43
+
44
+
45
+ class Runs:
46
+ def __init__(self, project: str):
47
+ self.project = project
48
+ self._runs = None
49
+
50
+ def _load_runs(self):
51
+ if self._runs is None:
52
+ run_names = SQLiteStorage.get_runs(self.project)
53
+ self._runs = [Run(self.project, name) for name in run_names]
54
+
55
+ def __iter__(self) -> Iterator[Run]:
56
+ self._load_runs()
57
+ return iter(self._runs)
58
+
59
+ def __getitem__(self, index: int) -> Run:
60
+ self._load_runs()
61
+ return self._runs[index]
62
+
63
+ def __len__(self) -> int:
64
+ self._load_runs()
65
+ return len(self._runs)
66
+
67
+ def __repr__(self) -> str:
68
+ self._load_runs()
69
+ return f"<Runs project={self.project} count={len(self._runs)}>"
70
+
71
+
72
+ class Api:
73
+ def runs(self, project: str) -> Runs:
74
+ if not SQLiteStorage.get_project_db_path(project).exists():
75
+ raise ValueError(f"Project '{project}' does not exist")
76
+ return Runs(project)
77
+
78
+ def alerts(
79
+ self,
80
+ project: str,
81
+ run: str | None = None,
82
+ level: str | None = None,
83
+ since: str | None = None,
84
+ ) -> list[dict]:
85
+ if not SQLiteStorage.get_project_db_path(project).exists():
86
+ raise ValueError(f"Project '{project}' does not exist")
87
+ return SQLiteStorage.get_alerts(project, run_name=run, level=level, since=since)
trackio/assets/badge.png ADDED
trackio/assets/trackio_logo_dark.png ADDED
trackio/assets/trackio_logo_light.png ADDED
trackio/assets/trackio_logo_old.png ADDED

Git LFS Details

  • SHA256: 3922c4d1e465270ad4d8abb12023f3beed5d9f7f338528a4c0ac21dcf358a1c8
  • Pointer size: 131 Bytes
  • Size of remote file: 487 kB
trackio/assets/trackio_logo_type_dark.png ADDED
trackio/assets/trackio_logo_type_dark_transparent.png ADDED
trackio/assets/trackio_logo_type_light.png ADDED
trackio/assets/trackio_logo_type_light_transparent.png ADDED