2626import re
2727from collections import defaultdict
2828
29+ from tqdm import tqdm
30+
2931from cometx .cli .admin_growth_render import build_html , write_html
3032from cometx .utils import format_time_key , get_next_time_key
3133
@@ -273,8 +275,14 @@ def build(self, workspaces):
273275 window = parse_window (self .window , now , self .units )
274276
275277 platforms = self ._resolve_platforms ()
278+ print ("Resolving workspaces..." )
276279 resolved_workspaces = self ._resolve_workspaces (workspaces )
280+ print (
281+ f"Collecting { ', ' .join (platforms ) or 'no' } data for "
282+ f"{ len (resolved_workspaces )} workspace(s)..."
283+ )
277284 events , usage , ran = self ._collect_selected (platforms , resolved_workspaces )
285+ print ("Building report..." )
278286
279287 return self ._assemble_report_data (
280288 events , usage , ran , resolved_workspaces , window
@@ -335,6 +343,7 @@ def _collect_selected(self, platforms, workspaces):
335343 usage : list = []
336344 ran = {"opik" : False , "em" : False , "mpm" : False }
337345 for platform in platforms :
346+ print (f"[{ PLATFORM_LABELS .get (platform , platform )} ] collecting..." )
338347 collector = getattr (self , self ._COLLECTOR_METHODS [platform ])
339348 platform_events , platform_usage = collector (workspaces )
340349 events .extend (platform_events )
@@ -784,6 +793,19 @@ def _assemble_report_data(self, events, usage, ran, workspaces, window):
784793 "sections" : {"unified" : unified_section , "products" : products },
785794 }
786795
796+ def _workspace_usage_metric (self , platform , metric , workspace , value , counts ):
797+ """Build the workspace-level (`project=None`) summary `UsageMetric`
798+ appended by every collector, so the summary shape lives in one place
799+ instead of being duplicated across EM/Opik/MPM."""
800+ return UsageMetric (
801+ platform = platform ,
802+ workspace = workspace ,
803+ metric = metric ,
804+ value = value ,
805+ project = None ,
806+ series = (continuous_series (dict (counts ), self .units ) if counts else []),
807+ )
808+
787809 def _collect_em (self , workspaces ):
788810 """Collect EM `em_project` CreationEvents + EXPERIMENT_COUNT /
789811 REGISTRY_MODELS / REGISTRY_VERSIONS UsageMetrics.
@@ -800,7 +822,7 @@ def _collect_em(self, workspaces):
800822 if self .limit is not None :
801823 workspaces = list (workspaces )[: self .limit ]
802824
803- for ws in workspaces :
825+ for ws in tqdm ( list ( workspaces ), desc = "EM workspaces" , unit = "ws" ) :
804826 try :
805827 response = self .api ._client .get_from_endpoint (
806828 "projects" , {"workspaceName" : ws }
@@ -829,7 +851,9 @@ def _collect_em(self, workspaces):
829851 ws_experiment_total = 0
830852 ws_counts : dict = defaultdict (int )
831853
832- for project in projects :
854+ for project in tqdm (
855+ projects , desc = f"EM { ws } " , unit = "proj" , leave = False
856+ ):
833857 proj_name = project .get ("projectName" )
834858 try :
835859 # Fetch the project's experiments once and reuse the list
@@ -871,15 +895,8 @@ def _collect_em(self, workspaces):
871895 continue
872896
873897 usage .append (
874- UsageMetric (
875- platform = "em" ,
876- workspace = ws ,
877- metric = "EXPERIMENT_COUNT" ,
878- value = ws_experiment_total ,
879- project = None ,
880- series = (
881- continuous_series (ws_counts , self .units ) if ws_counts else []
882- ),
898+ self ._workspace_usage_metric (
899+ "em" , "EXPERIMENT_COUNT" , ws , ws_experiment_total , ws_counts
883900 )
884901 )
885902
@@ -973,7 +990,7 @@ def _collect_opik(self, workspaces):
973990
974991 now = datetime .datetime .now (datetime .timezone .utc )
975992
976- for ws in workspaces :
993+ for ws in tqdm ( list ( workspaces ), desc = "Opik workspaces" , unit = "ws" ) :
977994 try :
978995 client = opik .Opik (workspace = ws , api_key = api_key , host = host )
979996 except Exception as exc :
@@ -1000,7 +1017,9 @@ def _collect_opik(self, workspaces):
10001017
10011018 ws_counts : dict = defaultdict (float )
10021019
1003- for project in projects :
1020+ for project in tqdm (
1021+ projects , desc = f"Opik { ws } " , unit = "proj" , leave = False
1022+ ):
10041023 try :
10051024 if project .created_at is not None :
10061025 events .append (
@@ -1054,17 +1073,8 @@ def _collect_opik(self, workspaces):
10541073 continue
10551074
10561075 usage .append (
1057- UsageMetric (
1058- platform = "opik" ,
1059- workspace = ws ,
1060- metric = "SPAN_COUNT" ,
1061- value = sum (ws_counts .values ()),
1062- project = None ,
1063- series = (
1064- continuous_series (dict (ws_counts ), self .units )
1065- if ws_counts
1066- else []
1067- ),
1076+ self ._workspace_usage_metric (
1077+ "opik" , "SPAN_COUNT" , ws , sum (ws_counts .values ()), ws_counts
10681078 )
10691079 )
10701080
@@ -1113,20 +1123,24 @@ def _collect_mpm(self, workspaces):
11131123 )
11141124
11151125 requested = set (workspaces )
1116- for ws_entry in all_workspaces :
1126+ selected_entries = [
1127+ ws_entry
1128+ for ws_entry in all_workspaces
11171129 # The MPM inventory shape is not verifiable live; guard against
11181130 # malformed elements so one bad entry can't crash the report.
1119- if not isinstance (ws_entry , dict ):
1120- continue
1131+ if isinstance (ws_entry , dict )
1132+ and ws_entry .get ("workspaceName" ) in requested
1133+ ]
1134+ for ws_entry in tqdm (selected_entries , desc = "MPM workspaces" , unit = "ws" ):
11211135 ws = ws_entry .get ("workspaceName" )
1122- if ws not in requested :
1123- continue
11241136
11251137 models = ws_entry .get ("models" , []) or []
11261138 ws_counts : dict = defaultdict (float )
11271139 ws_total = 0.0
11281140
1129- for model in models :
1141+ for model in tqdm (
1142+ models , desc = f"MPM { ws } " , unit = "model" , leave = False
1143+ ):
11301144 if not isinstance (model , dict ):
11311145 continue
11321146 model_name = model .get ("modelName" )
@@ -1176,17 +1190,8 @@ def _collect_mpm(self, workspaces):
11761190 continue
11771191
11781192 usage .append (
1179- UsageMetric (
1180- platform = "mpm" ,
1181- workspace = ws ,
1182- metric = "PREDICTION_VOLUME" ,
1183- value = ws_total ,
1184- project = None ,
1185- series = (
1186- continuous_series (dict (ws_counts ), self .units )
1187- if ws_counts
1188- else []
1189- ),
1193+ self ._workspace_usage_metric (
1194+ "mpm" , "PREDICTION_VOLUME" , ws , ws_total , ws_counts
11901195 )
11911196 )
11921197
0 commit comments