openrunner-sdk 2.18.0__tar.gz → 2.18.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/PKG-INFO +1 -1
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/__init__.py +1 -1
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/install_commands.py +142 -137
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/pyproject.toml +1 -1
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/.gitignore +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/=6.0 +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/=8.1 +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/README.md +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/CLAUDE.md +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/api_client.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/artifact.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/buffer.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/cache.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/cli.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/config.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/cost.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/dataset.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/environment.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/evaluation.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/feedback.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/git_info.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/guardrails.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/integration/__init__.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/integration/accelerate.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/integration/anthropic_tracer.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/integration/catboost.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/integration/diffusers.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/integration/fastai.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/integration/forced_alignment.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/integration/gladia.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/integration/gymnasium.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/integration/huggingface.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/integration/hydra.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/integration/ignite.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/integration/jax.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/integration/keras.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/integration/langchain.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/integration/lightgbm.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/integration/lightning.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/integration/llamaindex.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/integration/openai_finetune.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/integration/openai_tracer.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/integration/optuna.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/integration/pytorch.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/integration/sb3.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/integration/sklearn.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/integration/tensorflow.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/integration/trl.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/integration/tts.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/integration/ultralytics.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/integration/voice_agent.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/integration/whisper.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/integration/xgboost.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/launch.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/mcp_server.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/media.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/migrate.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/model.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/offline.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/pii.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/plot.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/prompt.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/query_api.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/redact.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/run.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/scorers.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/sender.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/session.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/settings.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/summary.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/sweep.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/system_metrics.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/tensorboard.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/trace.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/transcript_formatter.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/wal.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/wandb_compat/__init__.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/wandb_compat/_shim.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/openrunner/wer.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/tests/__init__.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/tests/conftest.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/tests/test_alert.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/tests/test_aliases.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/tests/test_api_client.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/tests/test_artifact.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/tests/test_buffer.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/tests/test_cache.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/tests/test_class_scorers.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/tests/test_cli.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/tests/test_config.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/tests/test_evaluation.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/tests/test_finish.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/tests/test_git_info.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/tests/test_init.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/tests/test_integration_fastai.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/tests/test_integration_huggingface.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/tests/test_integration_keras.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/tests/test_integration_langchain.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/tests/test_integration_lightning.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/tests/test_integration_pytorch.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/tests/test_integration_sklearn.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/tests/test_integration_xgboost.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/tests/test_launch.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/tests/test_log.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/tests/test_log_code.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/tests/test_media.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/tests/test_migrate.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/tests/test_offline.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/tests/test_offline_sync.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/tests/test_pii.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/tests/test_plot.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/tests/test_query_api.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/tests/test_resume.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/tests/test_sdk_features.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/tests/test_sender.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/tests/test_summary.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/tests/test_sweep.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/tests/test_system_metrics.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/tests/test_trace.py +0 -0
- {openrunner_sdk-2.18.0 → openrunner_sdk-2.18.2}/tests/test_wandb_compat.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: openrunner-sdk
|
|
3
|
-
Version: 2.18.
|
|
3
|
+
Version: 2.18.2
|
|
4
4
|
Summary: OpenRunner SDK - W&B-compatible ML experiment tracking client
|
|
5
5
|
Project-URL: Homepage, https://github.com/jqueguiner/openrunner
|
|
6
6
|
Project-URL: Repository, https://github.com/jqueguiner/openrunner
|
|
@@ -120,7 +120,7 @@ launch.from_run = _launch_from_run # type: ignore[attr-defined]
|
|
|
120
120
|
# openrunner.trace.patch_openai() syntax
|
|
121
121
|
trace.patch_openai = _patch_openai # type: ignore[attr-defined]
|
|
122
122
|
|
|
123
|
-
__version__ = "2.18.
|
|
123
|
+
__version__ = "2.18.2"
|
|
124
124
|
|
|
125
125
|
logger = logging.getLogger("openrunner")
|
|
126
126
|
|
|
@@ -504,11 +504,12 @@ if not config.get('api_key'):
|
|
|
504
504
|
|
|
505
505
|
client = APIClient(base_url=config['base_url'], api_key=config['api_key'])
|
|
506
506
|
|
|
507
|
-
# Resolve project
|
|
507
|
+
# Resolve project (case-insensitive)
|
|
508
508
|
project_name = config.get('project', '')
|
|
509
509
|
project_id = None
|
|
510
510
|
for p in client.list_projects():
|
|
511
|
-
|
|
511
|
+
full = f'{{p.get(\"org_name\",\"\")}}/{{p.get(\"name\",\"\")}}'
|
|
512
|
+
if full.lower() == project_name.lower() or (p.get('name') or '').lower() == project_name.lower():
|
|
512
513
|
project_id = p.get('id')
|
|
513
514
|
break
|
|
514
515
|
|
|
@@ -559,152 +560,156 @@ while True:
|
|
|
559
560
|
else:
|
|
560
561
|
resp = client._request('get', f'/projects/{{project_id}}/runs', params={{'limit': 10, 'order': 'desc'}})
|
|
561
562
|
runs_data = resp.json()
|
|
562
|
-
|
|
563
|
+
if isinstance(runs_data, dict) and 'detail' in runs_data:
|
|
564
|
+
print('API_ERROR=%s' % runs_data['detail'])
|
|
565
|
+
break
|
|
566
|
+
if isinstance(runs_data, dict):
|
|
567
|
+
runs = runs_data.get('runs', [])
|
|
568
|
+
elif isinstance(runs_data, list):
|
|
569
|
+
runs = runs_data
|
|
570
|
+
else:
|
|
571
|
+
runs = []
|
|
563
572
|
if not runs:
|
|
564
573
|
print('NO_RUNS')
|
|
565
|
-
|
|
566
|
-
sys.exit(1)
|
|
567
|
-
|
|
568
|
-
# Collect metrics
|
|
569
|
-
bars = '▁▂▃▄▅▆▇█'
|
|
570
|
-
results = []
|
|
571
|
-
|
|
572
|
-
for run in runs[:10]:
|
|
573
|
-
rid = run.get('id', run) if isinstance(run, dict) else run
|
|
574
|
-
try:
|
|
575
|
-
keys_param = ','.join(metric_keys)
|
|
576
|
-
resp = client._request('get', f'/runs/{{rid}}/metrics', params={{'keys': keys_param}})
|
|
577
|
-
data = resp.json()
|
|
578
|
-
metrics = data.get('metrics', {{}})
|
|
579
|
-
if not metrics and not show_all:
|
|
580
|
-
continue
|
|
581
|
-
|
|
582
|
-
# If none of the requested metrics found, use whatever is available
|
|
583
|
-
found_any = any(k in metrics for k in metric_keys)
|
|
584
|
-
if not found_any and metrics and not show_all:
|
|
585
|
-
metric_keys = list(metrics.keys())[:2]
|
|
586
|
-
|
|
587
|
-
for key, points in metrics.items():
|
|
588
|
-
if not show_all and key not in metric_keys:
|
|
589
|
-
continue
|
|
590
|
-
if not points:
|
|
591
|
-
continue
|
|
574
|
+
break
|
|
592
575
|
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
576
|
+
# Collect metrics
|
|
577
|
+
bars = '▁▂▃▄▅▆▇█'
|
|
578
|
+
results = []
|
|
579
|
+
|
|
580
|
+
for run in runs[:10]:
|
|
581
|
+
rid = run.get('id', run) if isinstance(run, dict) else run
|
|
582
|
+
try:
|
|
583
|
+
keys_param = ','.join(metric_keys)
|
|
584
|
+
resp = client._request('get', f'/runs/{{rid}}/metrics', params={{'keys': keys_param}})
|
|
585
|
+
data = resp.json()
|
|
586
|
+
metrics = data.get('metrics', {{}})
|
|
587
|
+
if not metrics and not show_all:
|
|
597
588
|
continue
|
|
598
589
|
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
'
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
'
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
590
|
+
# If none of the requested metrics found, use whatever is available
|
|
591
|
+
found_any = any(k in metrics for k in metric_keys)
|
|
592
|
+
if not found_any and metrics and not show_all:
|
|
593
|
+
metric_keys = list(metrics.keys())[:2]
|
|
594
|
+
|
|
595
|
+
for key, points in metrics.items():
|
|
596
|
+
if not show_all and key not in metric_keys:
|
|
597
|
+
continue
|
|
598
|
+
if not points:
|
|
599
|
+
continue
|
|
600
|
+
|
|
601
|
+
values = [pt.get('value', pt) if isinstance(pt, dict) else pt for pt in points]
|
|
602
|
+
steps = [pt.get('step', i) if isinstance(pt, dict) else i for i, pt in enumerate(points)]
|
|
603
|
+
values = [v for v in values if isinstance(v, (int, float))]
|
|
604
|
+
if not values:
|
|
605
|
+
continue
|
|
606
|
+
|
|
607
|
+
min_v = min(values)
|
|
608
|
+
max_v = max(values)
|
|
609
|
+
range_v = max_v - min_v or 1
|
|
610
|
+
w = 60
|
|
611
|
+
|
|
612
|
+
# Sample if too many
|
|
613
|
+
if len(values) > w:
|
|
614
|
+
step_size = len(values) / w
|
|
615
|
+
sampled = [values[int(j * step_size)] for j in range(w)]
|
|
616
|
+
else:
|
|
617
|
+
sampled = values
|
|
618
|
+
|
|
619
|
+
sparkline = ''
|
|
620
|
+
for v in sampled:
|
|
621
|
+
idx = int((v - min_v) / range_v * (len(bars) - 1))
|
|
622
|
+
sparkline += bars[idx]
|
|
623
|
+
|
|
624
|
+
run_name = run.get('display_name') or run.get('name') or rid[:8] if isinstance(run, dict) else rid[:8]
|
|
625
|
+
run_state = run.get('state', 'unknown') if isinstance(run, dict) else 'unknown'
|
|
626
|
+
direction = 'rising' if values[-1] > values[0] else 'falling'
|
|
627
|
+
pct = ((values[-1] - values[0]) / (values[0] or 1)) * 100
|
|
628
|
+
|
|
629
|
+
results.append({{
|
|
630
|
+
'run_id': rid,
|
|
631
|
+
'run_name': run_name,
|
|
632
|
+
'metric': key,
|
|
633
|
+
'sparkline': sparkline,
|
|
634
|
+
'min': min_v,
|
|
635
|
+
'max': max_v,
|
|
636
|
+
'latest': values[-1],
|
|
637
|
+
'steps': len(values),
|
|
638
|
+
'step_range': f'{{steps[0]}}->{{steps[-1]}}',
|
|
639
|
+
'direction': direction,
|
|
640
|
+
'pct': pct,
|
|
641
|
+
'state': run_state,
|
|
642
|
+
}})
|
|
643
|
+
except Exception as e:
|
|
644
|
+
results.append({{'run_id': rid, 'error': str(e)}})
|
|
645
|
+
|
|
646
|
+
if not results:
|
|
647
|
+
print('NO_METRICS')
|
|
648
|
+
break
|
|
647
649
|
|
|
648
|
-
|
|
649
|
-
if 'error' in r:
|
|
650
|
-
print(f' {{r[\"run_id\"][:8]}} — error: {{r[\"error\"]}}')
|
|
651
|
-
continue
|
|
652
|
-
print()
|
|
653
|
-
print(f' Run: {{r[\"run_name\"]}} ({{r[\"run_id\"][:8]}})')
|
|
654
|
-
print(f' Metric: {{r[\"metric\"]}} | Steps: {{r[\"step_range\"]}} ({{r[\"steps\"]}} pts)')
|
|
655
|
-
print(' Range: %.6f -> %.6f | Latest: %.6f' % (r['min'], r['max'], r['latest']))
|
|
656
|
-
print(' ' + r['sparkline'])
|
|
657
|
-
arrow = '↗' if r['pct'] > 0 else '↘'
|
|
658
|
-
print(' %s %s (%+.1f%%)' % (arrow, r['direction'], r['pct']))
|
|
659
|
-
|
|
660
|
-
# Summary table
|
|
661
|
-
print()
|
|
662
|
-
print('-' * 72)
|
|
663
|
-
print(' %-20s %-15s %10s %10s %10s %8s' % ('Run', 'Metric', 'Latest', 'Min', 'Max', 'Trend'))
|
|
664
|
-
print('-' * 72)
|
|
665
|
-
for r in results:
|
|
666
|
-
if 'error' in r:
|
|
667
|
-
continue
|
|
668
|
-
name = (r['run_name'] or '')[:20]
|
|
669
|
-
met = r['metric'][:15]
|
|
670
|
-
arrow = '↗' if r['pct'] > 0 else '↘'
|
|
671
|
-
trend = '%s%+.0f%%' % (arrow, r['pct'])
|
|
672
|
-
print(' %-20s %-15s %10.4f %10.4f %10.4f %8s' % (name, met, r['latest'], r['min'], r['max'], trend))
|
|
673
|
-
print('-' * 72)
|
|
674
|
-
|
|
675
|
-
# Live runs footer — show link + loss indicator for in-progress runs
|
|
676
|
-
base_url = config.get('base_url', '').rstrip('/')
|
|
677
|
-
live_runs = [r for r in results if r.get('state') in ('running', 'in_progress') and 'error' not in r]
|
|
678
|
-
if live_runs:
|
|
679
|
-
print()
|
|
650
|
+
# ASCII output
|
|
680
651
|
print('=' * 72)
|
|
681
|
-
print('
|
|
652
|
+
print(f' OPENRUNNER METRICS — {{project_name}}')
|
|
682
653
|
print('=' * 72)
|
|
683
|
-
|
|
684
|
-
for r in
|
|
685
|
-
if
|
|
654
|
+
|
|
655
|
+
for r in results:
|
|
656
|
+
if 'error' in r:
|
|
657
|
+
print(f' {{r[\"run_id\"][:8]}} — error: {{r[\"error\"]}}')
|
|
686
658
|
continue
|
|
687
|
-
seen_ids.add(r['run_id'])
|
|
688
|
-
# Loss indicator
|
|
689
|
-
loss_metrics = [x for x in live_runs if x['run_id'] == r['run_id'] and 'loss' in x['metric'].lower()]
|
|
690
|
-
lr_metrics = [x for x in live_runs if x['run_id'] == r['run_id'] and 'lr' in x['metric'].lower() or 'learning' in x['metric'].lower()]
|
|
691
|
-
indicator = ''
|
|
692
|
-
if loss_metrics:
|
|
693
|
-
lm = loss_metrics[0]
|
|
694
|
-
arrow = '↘' if lm['pct'] < 0 else '↗'
|
|
695
|
-
indicator += ' loss: %.4f %s' % (lm['latest'], arrow)
|
|
696
|
-
if lr_metrics:
|
|
697
|
-
lrm = lr_metrics[0]
|
|
698
|
-
indicator += ' | lr: %.2e' % lrm['latest']
|
|
699
|
-
run_url = '%s/%s/runs/%s' % (base_url, project_name, r['run_id'])
|
|
700
659
|
print()
|
|
701
|
-
print('
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
660
|
+
print(f' Run: {{r[\"run_name\"]}} ({{r[\"run_id\"][:8]}})')
|
|
661
|
+
print(f' Metric: {{r[\"metric\"]}} | Steps: {{r[\"step_range\"]}} ({{r[\"steps\"]}} pts)')
|
|
662
|
+
print(' Range: %.6f -> %.6f | Latest: %.6f' % (r['min'], r['max'], r['latest']))
|
|
663
|
+
print(' ' + r['sparkline'])
|
|
664
|
+
arrow = '↗' if r['pct'] > 0 else '↘'
|
|
665
|
+
print(' %s %s (%+.1f%%)' % (arrow, r['direction'], r['pct']))
|
|
666
|
+
|
|
667
|
+
# Summary table
|
|
706
668
|
print()
|
|
707
|
-
print('
|
|
669
|
+
print('-' * 72)
|
|
670
|
+
print(' %-20s %-15s %10s %10s %10s %8s' % ('Run', 'Metric', 'Latest', 'Min', 'Max', 'Trend'))
|
|
671
|
+
print('-' * 72)
|
|
672
|
+
for r in results:
|
|
673
|
+
if 'error' in r:
|
|
674
|
+
continue
|
|
675
|
+
name = (r['run_name'] or '')[:20]
|
|
676
|
+
met = r['metric'][:15]
|
|
677
|
+
arrow = '↗' if r['pct'] > 0 else '↘'
|
|
678
|
+
trend = '%s%+.0f%%' % (arrow, r['pct'])
|
|
679
|
+
print(' %-20s %-15s %10.4f %10.4f %10.4f %8s' % (name, met, r['latest'], r['min'], r['max'], trend))
|
|
680
|
+
print('-' * 72)
|
|
681
|
+
|
|
682
|
+
# Live runs footer — show link + loss indicator for in-progress runs
|
|
683
|
+
base_url = config.get('base_url', '').rstrip('/')
|
|
684
|
+
live_runs = [r for r in results if r.get('state') in ('running', 'in_progress') and 'error' not in r]
|
|
685
|
+
if live_runs:
|
|
686
|
+
print()
|
|
687
|
+
print('=' * 72)
|
|
688
|
+
print(' LIVE RUNS')
|
|
689
|
+
print('=' * 72)
|
|
690
|
+
seen_ids = set()
|
|
691
|
+
for r in live_runs:
|
|
692
|
+
if r['run_id'] in seen_ids:
|
|
693
|
+
continue
|
|
694
|
+
seen_ids.add(r['run_id'])
|
|
695
|
+
loss_metrics = [x for x in live_runs if x['run_id'] == r['run_id'] and 'loss' in x['metric'].lower()]
|
|
696
|
+
lr_metrics = [x for x in live_runs if x['run_id'] == r['run_id'] and ('lr' in x['metric'].lower() or 'learning' in x['metric'].lower())]
|
|
697
|
+
indicator = ''
|
|
698
|
+
if loss_metrics:
|
|
699
|
+
lm = loss_metrics[0]
|
|
700
|
+
arrow = '↘' if lm['pct'] < 0 else '↗'
|
|
701
|
+
indicator += ' loss: %.4f %s' % (lm['latest'], arrow)
|
|
702
|
+
if lr_metrics:
|
|
703
|
+
lrm = lr_metrics[0]
|
|
704
|
+
indicator += ' | lr: %.2e' % lrm['latest']
|
|
705
|
+
run_url = '%s/%s/runs/%s' % (base_url, project_name, r['run_id'])
|
|
706
|
+
print()
|
|
707
|
+
print(' %s %s' % (r['run_name'], indicator))
|
|
708
|
+
if loss_metrics:
|
|
709
|
+
print(' %s' % loss_metrics[0]['sparkline'])
|
|
710
|
+
print(' -> %s' % run_url)
|
|
711
|
+
print()
|
|
712
|
+
print('=' * 72)
|
|
708
713
|
|
|
709
714
|
# Watch mode: loop or exit
|
|
710
715
|
if not watch_mode:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|