Skip to content

Commit

Permalink
v0.0.2 (#23)
Browse files Browse the repository at this point in the history
**功能更新**

- [x] 记录终端的打印日志,捕获错误 @SAKURA-CAT @Feudalman 
- [x] 日志文件结构调整(不再兼容0.0.1版本日志结构) @SAKURA-CAT 

**前端更新**

- [x] 错误页面 @Feudalman @SAKURA-CAT 
- [x] 修改图表分组名称与样式 @Feudalman 
- [x] 修改默认项目名称 @Feudalman 
- [x] 图表样式(折线图)更新,标题加粗 @SAKURA-CAT 

**其他更新**

- [x] 优化终端打印信息 @SAKURA-CAT @Feudalman 
- [x] 图表颜色选用 @xiaolin199912 
- [x] 实验排序改为倒序 #20  @Feudalman 
- [x] 用host参数代替share参数 #17 @SAKURA-CAT 

---------

Co-authored-by: KAAANG <cunykang@gmail.com>
Co-authored-by: ZeYi Lin <58305964+xiaolin199912@users.noreply.github.com>
Co-authored-by: KAAANG <79990647+SAKURA-CAT@users.noreply.github.com>
  • Loading branch information
4 people authored Dec 17, 2023
1 parent 79b504f commit 239ac27
Show file tree
Hide file tree
Showing 76 changed files with 1,676 additions and 484 deletions.
3 changes: 3 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,6 @@ dist/
package.json

*.md


swanlab/
29 changes: 29 additions & 0 deletions .github/ISSUE_TEMPLATE/bug提交.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
name: Bug提交
about: 向开发者们反映出现的bug
title: '[BUG] '
labels: BUG
assignees: ''
---

## Bug 描述

> 描述 bug 的主要内容
## 如何复现

> 在此处向开发者描述 bug 的复现过程,在必要时请附上截图
1. 前往 '....'

2. 点击 '....'

3. 出现如下问题 '....'

## 预期行为

> 向开发者描述如果没有此 bug,应该是什么样的
## 录屏

> 如果需要,可以附上截图
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package-lock.json
pnpm-lock.yaml
vue/components.d.ts
vue/auto-imports.d.ts
swanlog/

# Byte-compiled / optimized / DLL files
__pycache__/
Expand Down
2 changes: 2 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,5 @@ README.md
doc/**

**.md

swanlab/
27 changes: 10 additions & 17 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,6 @@
"runtimeExecutable": "npm",
"runtimeArgs": ["run", "dev:mock"]
},
// 启动前端编译服务
{
"name": "编译前端项目",
"request": "launch",
"cwd": "${workspaceRoot}",
"type": "node",
"runtimeExecutable": "npm",
"runtimeArgs": ["run", "build"]
},
// 启动后端开发服务
{
"name": "后端开发",
Expand All @@ -42,25 +33,27 @@
//sys.path 会加入顶层目录,影响模块导入查询路径
"env": { "PYTHONPATH": "${workspaceFolder}" }
},
// 打包命令
{
"name": "开启一个实验",
"name": "构建项目",
"type": "python",
"request": "launch",
"program": "${workspaceFolder}/test/create_experiment.py",
"program": "${workspaceFolder}/build_pypi.py",
"console": "integratedTerminal",
"justMyCode": true,
"cwd": "${workspaceFolder}",
//sys.path 会加入顶层目录,影响模块导入查询路径
"env": { "PYTHONPATH": "${workspaceFolder}" }
"cwd": "${workspaceFolder}"
},
// 模拟实验开启
{
"name": "构建项目",
"name": "开启一个实验",
"type": "python",
"request": "launch",
"program": "${workspaceFolder}/build_pypi.py",
"program": "${workspaceFolder}/test/create_experiment.py",
"console": "integratedTerminal",
"justMyCode": true,
"cwd": "${workspaceFolder}"
"cwd": "${workspaceFolder}",
//sys.path 会加入顶层目录,影响模块导入查询路径
"env": { "PYTHONPATH": "${workspaceFolder}" }
},
// python运行当前文件
{
Expand Down
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"material-icon-theme.folders.associations": {
"swanlab": "api",
"wandb": "database",
".swanlab": "admin",
"swanlog": "log",
".config": "config",
"store": "database",
"help": "java",
Expand Down
2 changes: 1 addition & 1 deletion build_pypi.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import os

# 构建node项目
subprocess.run("npm run build", shell=True)
subprocess.run("npm run build.release", shell=True)
# 如果dist文件夹存在则删除
if os.path.exists("dist"):
shutil.rmtree("dist")
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
{
"name": "swanlab-ui",
"private": true,
"version": "0.0.1beta6",
"version": "0.0.2",
"type": "module",
"scripts": {
"dev": "vite",
"dev:mock": "vite --mode mock",
"build": "vite build",
"build.release": "vite build --mode release",
"preview": "vite preview"
},
"dependencies": {
Expand All @@ -16,6 +17,7 @@
"moment": "^2.29.4",
"pinia": "^2.1.7",
"sass": "^1.69.5",
"terser": "^5.26.0",
"vue": "^3.3.8",
"vue-i18n": "^9.8.0",
"vue-router": "^4.2.5",
Expand Down
3 changes: 3 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,6 @@ click
ujson
portalocker

# Information collection
psutil

30 changes: 27 additions & 3 deletions swanlab/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
from .database import sd
from .log import swanlog as swl
from .env import swc

_sd = None
"""
swandatabase对象
使用动态导入的方式有助于环境隔离
比如cli不需要此对象,就不需要导入
"""


def init(experiment_name: str = None, description: str = "", config: dict = {}):
Expand All @@ -13,11 +21,24 @@ def init(experiment_name: str = None, description: str = "", config: dict = {}):
config : dict, optional
实验可选配置,在此处可以记录一些实验的超参数等信息
"""
sd.init(
global _sd
if _sd is not None:
raise RuntimeError("swanlab has been initialized")
from .database import swandatabase as sd

# 挂载对象
_sd = sd
# 初始化数据库
_sd.init(
experiment_name=experiment_name,
description=description,
config=config,
)
# 初始化日志对象
swl.init(swc.output)
swl.info("Run data will be saved locally in " + swc.exp_folder)
swl.info("Experiment_name: " + _sd.experiment.name)
swl.info("Run `swanlab watch` to view SwanLab Experiment Dashboard")


def log(data: dict):
Expand All @@ -31,11 +52,14 @@ def log(data: dict):
data : dict
此处填写需要记录的数据
"""
if _sd is None:
raise RuntimeError("swanlab has not been initialized")

if not isinstance(data, dict):
raise TypeError("log data must be a dict")
for key in data:
# 遍历字典的key,记录到本地文件中
sd.add(key, data[key])
_sd.add(key, data[key])


__all__ = ["init", "log"]
61 changes: 40 additions & 21 deletions swanlab/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"""

import click
import uvicorn
from .utils import is_vaild_ip, is_available_port


@click.group()
Expand All @@ -18,38 +18,57 @@ def cli():


@cli.command()
# 控制服务发布的ip地址
@click.option(
"--share",
is_flag=True,
help="When shared, swanlab web will run on localhost",
)
@click.option(
"--debug",
is_flag=True,
help="Show more logs when use debug mode",
"--host",
"-h",
default="127.0.0.1",
type=str,
help="The host of swanlab web, default by 127.0.0.1",
callback=is_vaild_ip,
)
# 控制服务发布的端口,默认5092
@click.option(
"--port",
"-p",
default=5092,
type=int,
help="The port of swanlab web, default by 5092",
)
def watch(share, debug, port):
# 日志等级
@click.option(
"--log-level",
default="info",
type=click.Choice(["debug", "info", "warning", "error", "critical"]),
help="The level of log, default by info; You can choose one of [debug, info, warning, error, critical]",
)
def watch(log_level: str, host: tuple, port: int):
"""Run this command to turn on the swanlab service."""
# print("share", share)
# print("debug", debug)
# print("port", port)
# 导入必要的模块
from ..log import swanlog as swl
from ..server import app
import uvicorn

# 服务地址
host = "localhost" if share else "127.0.0.1"
# 日志等级
log_level = "info" if debug else "warning"
click.echo(f"swanlab running on \033[1mhttp://{host}:{port}\033[0m")
# ---------------------------------- 日志等级处理 ----------------------------------
swl.setLevel(log_level)
# ---------------------------------- 服务地址处理 ----------------------------------
# 拿到当前本机可用的所有ip地址
ip, ipv4 = host
ips = [f"http://{ip}:{port}" for ip in ipv4]
# 判断ip:port是否被占用
is_available_port(ip, port)
# ---------------------------------- 日志打印 ----------------------------------
if ip == "0.0.0.0":
# 检查每个ip地址的端口占用情况
swl.info(f"SwanLab Experiment Dashboard running...")
swl.info(f"Available on: \n" + "\n".join(ips))
else:
swl.info(f"SwanLab Experiment Dashboard running on \033[1mhttp://{ip}:{port}\033[0m")
# ---------------------------------- 启动服务 ----------------------------------

# 使用 uvicorn 启动 FastAPI 应用
uvicorn.run(app, host=host, port=port, log_level=log_level)
# 使用 uvicorn 启动 FastAPI 应用,关闭原生日志
uvicorn.run(app, host=ip, port=port, log_level="critical")


if __name__ == "__main__":
cli()
watch()
59 changes: 59 additions & 0 deletions swanlab/cli/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
r"""
@DATE: 2023-12-15 15:53:21
@File: swanlab/cli/utils.py
@IDE: vscode
@Description:
命令行工具
"""
import re
import psutil
import socket
import click


def is_vaild_ip(ctx, param, ip: str) -> tuple:
"""检测是否是合法的ip地址
Parameters
----------
ctx : click.Context
上下文
param : click.Parameter
参数
ip : str
带检测的字符串
"""
ip = str(ip)
pattern = re.compile(r"^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$")
if not pattern.match(ip):
raise click.BadParameter("Invalid IP address format: " + ip)
# 没有问题,获取当前机器的所有ip地址
interfaces = psutil.net_if_addrs()
ipv4 = []
for _, addresses in interfaces.items():
for address in addresses:
# 如果是ipv4地址
if address.family == socket.AddressFamily.AF_INET:
ipv4.append(address.address)
if ip not in ipv4 and ip != "0.0.0.0":
raise click.BadParameter("IP address '" + ip + "' should be one of " + str(ipv4) + ".")
return ip, ipv4


def is_available_port(host, port):
"""检测端口是否可用
Parameters
----------
host : str
ip地址
port : int
端口号
"""
try:
with socket.create_server((host, port), reuse_port=True):
pass
except:
raise OSError("Port '" + str(port) + "' is not available on " + host + ".")
Loading

0 comments on commit 239ac27

Please sign in to comment.