Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,7 @@ SwanLab会对AI训练过程中所使用的**硬件信息**和**资源使用情
- [FastAI](https://docs.swanlab.cn/guide_cloud/integration/integration-fastai.html)
- [LightGBM](https://docs.swanlab.cn/guide_cloud/integration/integration-lightgbm.html)
- [XGBoost](https://docs.swanlab.cn/guide_cloud/integration/integration-xgboost.html)
- [CatBoost](https://docs.swanlab.cn/guide_cloud/integration/integration-catboost.html)
- [MLX-LM](https://docs.swanlab.cn/guide_cloud/integration/integration-mlx-lm.html)

**评估框架**
Expand Down
1 change: 1 addition & 0 deletions README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,7 @@ Below is a list of frameworks we have integrated. Feel free to submit an [Issue]
- [FastAI](https://docs.swanlab.cn/en/guide_cloud/integration/integration-fastai.html)
- [LightGBM](https://docs.swanlab.cn/en/guide_cloud/integration/integration-lightgbm.html)
- [XGBoost](https://docs.swanlab.cn/en/guide_cloud/integration/integration-xgboost.html)
- [CatBoost](https://docs.swanlab.cn/en/guide_cloud/integration/integration-catboost.html)
- [MLX-LM](https://docs.swanlab.cn/en/guide_cloud/integration/integration-mlx-lm.html)

**Evaluation Frameworks**
Expand Down
1 change: 1 addition & 0 deletions README_JP.md
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,7 @@ swanlab login --host http://localhost:8000
- [FastAI](https://docs.swanlab.cn/en/guide_cloud/integration/integration-fastai.html)
- [LightGBM](https://docs.swanlab.cn/en/guide_cloud/integration/integration-lightgbm.html)
- [XGBoost](https://docs.swanlab.cn/en/guide_cloud/integration/integration-xgboost.html)
- [CatBoost](https://docs.swanlab.cn/en/guide_cloud/integration/integration-catboost.html)
- [MLX-LM](https://docs.swanlab.cn/en/guide_cloud/integration/integration-mlx-lm.html)

**コンピュータビジョン**
Expand Down
1 change: 1 addition & 0 deletions README_RU.md
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,7 @@ swanlab login --host http://localhost:8000
- [FastAI](https://docs.swanlab.cn/en/guide_cloud/integration/integration-fastai.html)
- [LightGBM](https://docs.swanlab.cn/en/guide_cloud/integration/integration-lightgbm.html)
- [XGBoost](https://docs.swanlab.cn/en/guide_cloud/integration/integration-xgboost.html)
- [CatBoost](https://docs.swanlab.cn/en/guide_cloud/integration/integration-catboost.html)
- [MLX-LM](https://docs.swanlab.cn/en/guide_cloud/integration/integration-mlx-lm.html)

**Компьютерное зрение**
Expand Down
9 changes: 9 additions & 0 deletions swanlab/core_python/uploader/upload.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
@description: 定义上传函数
"""

import time
from typing import List, Union, Literal, TypedDict

from swanlab.log import swanlog
Expand Down Expand Up @@ -69,6 +70,7 @@ def trace_metrics(
return
# 分批上传
if isinstance(data, dict):
need_split = len(data['metrics']) > per_request_len
# 1. 指标数据
for i in range(0, len(data['metrics']), per_request_len):
_, resp = getattr(client, method)(
Expand All @@ -81,13 +83,18 @@ def trace_metrics(
if resp.status_code == 202:
client.pending = True
return
if need_split:
time.sleep(1)
else:
need_split = len(data) > per_request_len
# 2. 列表数据(列等)
for i in range(0, len(data), per_request_len):
_, resp = getattr(client, method)(url, data[i : i + per_request_len])
if resp.status_code == 202:
client.pending = True
return
if need_split:
time.sleep(1)


@sync_error_handler
Expand Down Expand Up @@ -182,6 +189,8 @@ def upload_columns(columns: List[ColumnModel]):


__all__ = [
"trace_metrics",
"MetricDict",
"upload_logs",
"upload_media_metrics",
"upload_scalar_metrics",
Expand Down
4 changes: 2 additions & 2 deletions swanlab/data/porter/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import wrapt

from swanlab.core_python import get_client
from swanlab.core_python.uploader import ColumnModel, ScalarModel, MediaModel, LogModel
from swanlab.core_python.uploader import ColumnModel, ScalarModel, MediaModel
from swanlab.core_python.uploader.thread import ThreadPool, UploadType
from swanlab.data.store import RunStore, get_run_store, reset_run_store
from swanlab.env import create_time
Expand Down Expand Up @@ -531,7 +531,7 @@ def _filter_media_by_step(self, metric: MediaModel) -> bool:
"""
return filter_metric(metric.key, metric.step, self._run_store.metrics)

def _filter_log_by_epoch(self, log: LogContent) -> LogModel:
def _filter_log_by_epoch(self, log: LogContent) -> bool:
"""
筛选日志数据,排除已经上传的日志
:param log: 日志数据
Expand Down
5 changes: 3 additions & 2 deletions swanlab/data/run/metadata/cooperation/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
@description: 合作信息采集
"""

from typing import TypedDict, Optional
from typing import TypedDict, Optional, Union

from swanlab.core_python import get_client
from swanlab.env import get_mode, get_swanlog_dir
Expand All @@ -17,7 +17,7 @@ class SwanLabInfo(TypedDict):
version: str
mode: str
swanlog_dir: str
exp_url: str
exp_url: Union[str, None]


class CoopInfo(TypedDict):
Expand All @@ -41,6 +41,7 @@ def get_swanlab_info() -> SwanLabInfo:
"version": get_package_version(),
"mode": get_mode(),
"swanlog_dir": get_swanlog_dir(),
"exp_url": None,
}
try:
client = get_client()
Expand Down
5 changes: 4 additions & 1 deletion swanlab/data/run/webhook.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ def try_send_webhook():
webhook = os.getenv(SwanLabEnv.WEBHOOK.value)
if not webhook:
return
data = get_cooperation_info(swanlab=True)
value = os.getenv(SwanLabEnv.WEBHOOK_VALUE.value)
data = get_cooperation_info(swanlab=True) or {}
if value:
data["value"] = value
try:
requests.post(webhook, json=data)
except Exception as e: # noqa
Expand Down
4 changes: 4 additions & 0 deletions swanlab/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ class SwanLabEnv(enum.Enum):
"""
webhook地址。swanlab初始化完毕时,如果此环境变量存在,会调用此地址,发送消息。
"""
WEBHOOK_VALUE = "SWANLAB_WEBHOOK_VALUE"
"""
webhook发送的自定义内容,以字符串读取此环境变量值后发送
"""
DESCRIPTION = "SWANLAB_DESCRIPTION"
"""
实验描述,用于为实验提供更详细的介绍或标注
Expand Down
48 changes: 48 additions & 0 deletions test/unit/core_python/uploader/test_upload.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
"""
@author: cunyue
@file: test_upload.py
@time: 2025/11/9 18:55
@description: 测试上传
"""

import time
from typing import List
from unittest.mock import patch, MagicMock

import pytest

from swanlab.core_python.uploader.upload import trace_metrics, MetricDict


@pytest.fixture
def mock_client():
client = MagicMock()
client.pending = False
return client


def mock_metrics(metrics: List[dict]) -> MetricDict:
return {
"projectId": "proj_123",
"experimentId": "exp_456",
"type": "scalar",
"metrics": metrics,
"flagId": None,
}


def test_trace_metrics_does_not_upload_when_client_is_pending(mock_client):
with patch("swanlab.core_python.uploader.upload.get_client", return_value=mock_client):
mock_client.pending = True
trace_metrics("/test/url", data=mock_metrics([]))
mock_client.post.assert_not_called()


def test_trace_metrics_uploads_all_metrics_in_batches(mock_client):
with patch("swanlab.core_python.uploader.upload.get_client", return_value=mock_client):
mock_client.post.return_value = (None, MagicMock(status_code=200))
start = time.time()
trace_metrics("/test/url", data=mock_metrics([{"key": "value"}] * 2500), per_request_len=1000)
assert mock_client.post.call_count == 3
end = time.time()
assert end - start > 3