deepboard 0.2.0__py3-none-any.whl
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.
- deepboard/__init__.py +1 -0
- deepboard/__version__.py +4 -0
- deepboard/gui/THEME.yml +28 -0
- deepboard/gui/__init__.py +0 -0
- deepboard/gui/assets/artefacts.css +108 -0
- deepboard/gui/assets/base.css +208 -0
- deepboard/gui/assets/base.js +77 -0
- deepboard/gui/assets/charts.css +188 -0
- deepboard/gui/assets/compare.css +90 -0
- deepboard/gui/assets/datagrid.css +120 -0
- deepboard/gui/assets/fileview.css +13 -0
- deepboard/gui/assets/right_panel.css +227 -0
- deepboard/gui/assets/theme.css +85 -0
- deepboard/gui/components/__init__.py +8 -0
- deepboard/gui/components/artefact_group.py +12 -0
- deepboard/gui/components/chart_type.py +22 -0
- deepboard/gui/components/legend.py +34 -0
- deepboard/gui/components/log_selector.py +22 -0
- deepboard/gui/components/modal.py +20 -0
- deepboard/gui/components/smoother.py +21 -0
- deepboard/gui/components/split_selector.py +21 -0
- deepboard/gui/components/stat_line.py +8 -0
- deepboard/gui/entry.py +21 -0
- deepboard/gui/main.py +93 -0
- deepboard/gui/pages/__init__.py +1 -0
- deepboard/gui/pages/compare_page/__init__.py +6 -0
- deepboard/gui/pages/compare_page/compare_page.py +22 -0
- deepboard/gui/pages/compare_page/components/__init__.py +4 -0
- deepboard/gui/pages/compare_page/components/card_list.py +19 -0
- deepboard/gui/pages/compare_page/components/chart.py +54 -0
- deepboard/gui/pages/compare_page/components/compare_setup.py +30 -0
- deepboard/gui/pages/compare_page/components/split_card.py +51 -0
- deepboard/gui/pages/compare_page/components/utils.py +20 -0
- deepboard/gui/pages/compare_page/routes.py +58 -0
- deepboard/gui/pages/main_page/__init__.py +4 -0
- deepboard/gui/pages/main_page/datagrid/__init__.py +5 -0
- deepboard/gui/pages/main_page/datagrid/compare_button.py +21 -0
- deepboard/gui/pages/main_page/datagrid/datagrid.py +67 -0
- deepboard/gui/pages/main_page/datagrid/handlers.py +54 -0
- deepboard/gui/pages/main_page/datagrid/header.py +43 -0
- deepboard/gui/pages/main_page/datagrid/routes.py +112 -0
- deepboard/gui/pages/main_page/datagrid/row.py +20 -0
- deepboard/gui/pages/main_page/datagrid/sortable_column_js.py +45 -0
- deepboard/gui/pages/main_page/datagrid/utils.py +9 -0
- deepboard/gui/pages/main_page/handlers.py +16 -0
- deepboard/gui/pages/main_page/main_page.py +21 -0
- deepboard/gui/pages/main_page/right_panel/__init__.py +12 -0
- deepboard/gui/pages/main_page/right_panel/config.py +57 -0
- deepboard/gui/pages/main_page/right_panel/fragments.py +133 -0
- deepboard/gui/pages/main_page/right_panel/hparams.py +25 -0
- deepboard/gui/pages/main_page/right_panel/images.py +358 -0
- deepboard/gui/pages/main_page/right_panel/run_info.py +86 -0
- deepboard/gui/pages/main_page/right_panel/scalars.py +251 -0
- deepboard/gui/pages/main_page/right_panel/template.py +151 -0
- deepboard/gui/pages/main_page/routes.py +25 -0
- deepboard/gui/pages/not_found.py +3 -0
- deepboard/gui/requirements.txt +5 -0
- deepboard/gui/utils.py +267 -0
- deepboard/resultTable/__init__.py +2 -0
- deepboard/resultTable/cursor.py +20 -0
- deepboard/resultTable/logwritter.py +667 -0
- deepboard/resultTable/resultTable.py +529 -0
- deepboard/resultTable/scalar.py +29 -0
- deepboard/resultTable/table_schema.py +135 -0
- deepboard/resultTable/utils.py +50 -0
- deepboard-0.2.0.dist-info/METADATA +164 -0
- deepboard-0.2.0.dist-info/RECORD +69 -0
- deepboard-0.2.0.dist-info/WHEEL +4 -0
- deepboard-0.2.0.dist-info/entry_points.txt +2 -0
@@ -0,0 +1,112 @@
|
|
1
|
+
from typing import *
|
2
|
+
from fasthtml.common import *
|
3
|
+
from .datagrid import DataGrid
|
4
|
+
from .compare_button import CompareButton
|
5
|
+
from ..main_page import MainPage
|
6
|
+
|
7
|
+
def build_datagrid_endpoints(rt):
|
8
|
+
rt("/hide")(hide_column)
|
9
|
+
rt("/show")(show_column)
|
10
|
+
rt("/rename_col_datagrid")(get_rename_column)
|
11
|
+
rt("/rename_col", methods=["POST"])(post_rename_column)
|
12
|
+
rt("/sort")(sort)
|
13
|
+
rt("/reorder_columns", methods=["POST"])(reorder_columns)
|
14
|
+
rt("/shift_click_row")(shift_click_row) # Endpoint is called in the javascript file
|
15
|
+
rt("/hide_run")(hide_run)
|
16
|
+
rt("/show_run")(show_run)
|
17
|
+
rt("/show_hidden")(show_hidden)
|
18
|
+
rt("/hide_hidden")(hide_hidden)
|
19
|
+
rt("/compare_action")(compare_action)
|
20
|
+
|
21
|
+
async def hide_column(session, col: str):
|
22
|
+
from __main__ import rTable
|
23
|
+
rTable.hide_column(col)
|
24
|
+
|
25
|
+
# Return the datagrid
|
26
|
+
return DataGrid(session)
|
27
|
+
|
28
|
+
async def show_column(session, col: str, after: str):
|
29
|
+
from __main__ import rTable
|
30
|
+
cols = rTable.result_columns
|
31
|
+
if after not in cols:
|
32
|
+
print(f"[WARNING]: Did not find column: {after}")
|
33
|
+
return DataGrid(session)
|
34
|
+
pos = cols[after][0] + 1
|
35
|
+
print(f"Show column: {col} after {after} position {pos}")
|
36
|
+
rTable.show_column(col, pos)
|
37
|
+
|
38
|
+
# Return the datagrid
|
39
|
+
return DataGrid(session)
|
40
|
+
|
41
|
+
async def get_rename_column(session, col: str):
|
42
|
+
from __main__ import rTable
|
43
|
+
if col not in rTable.result_columns:
|
44
|
+
print(f"[WARNING]: Did not find column: {col}")
|
45
|
+
return DataGrid(session)
|
46
|
+
return DataGrid(session, rename_col=col)
|
47
|
+
|
48
|
+
async def post_rename_column(session, col_id: str, new_name: str):
|
49
|
+
from __main__ import rTable
|
50
|
+
if col_id not in rTable.result_columns:
|
51
|
+
print(f"[WARNING]: Did not find column: {col_id}")
|
52
|
+
return DataGrid(session)
|
53
|
+
rTable.set_column_alias({col_id: new_name})
|
54
|
+
|
55
|
+
# Return the datagrid
|
56
|
+
return DataGrid(session)
|
57
|
+
|
58
|
+
async def sort(session, by: str, order: str):
|
59
|
+
if "datagrid" not in session:
|
60
|
+
session["datagrid"] = dict(
|
61
|
+
sort_by=None,
|
62
|
+
sort_order=None
|
63
|
+
)
|
64
|
+
session["datagrid"]["sort_by"] = by
|
65
|
+
session["datagrid"]["sort_order"] = order
|
66
|
+
return DataGrid(session)
|
67
|
+
|
68
|
+
async def reorder_columns(session, order: str):
|
69
|
+
from __main__ import rTable
|
70
|
+
order = order.split(",")
|
71
|
+
prep_order = {col_id: i + 1 for i, col_id in enumerate(order)}
|
72
|
+
rTable.set_column_order(prep_order)
|
73
|
+
return DataGrid(session)
|
74
|
+
|
75
|
+
async def shift_click_row(session, run_id: int):
|
76
|
+
if "datagrid" not in session:
|
77
|
+
session["datagrid"] = dict()
|
78
|
+
|
79
|
+
session["datagrid"]["multiselection"] = True
|
80
|
+
if "selected-rows" not in session["datagrid"]:
|
81
|
+
session["datagrid"]["selected-rows"] = []
|
82
|
+
|
83
|
+
if run_id in session["datagrid"]["selected-rows"]:
|
84
|
+
session["datagrid"]["selected-rows"].remove(run_id)
|
85
|
+
else:
|
86
|
+
session["datagrid"]["selected-rows"].append(run_id)
|
87
|
+
|
88
|
+
return DataGrid(session), CompareButton(session, swap=True)
|
89
|
+
|
90
|
+
async def hide_run(session, run_id: int):
|
91
|
+
from __main__ import rTable
|
92
|
+
rTable.hide_run(run_id)
|
93
|
+
return DataGrid(session)
|
94
|
+
|
95
|
+
async def show_run(session, run_id: int):
|
96
|
+
from __main__ import rTable
|
97
|
+
rTable.show_run(run_id)
|
98
|
+
return DataGrid(session)
|
99
|
+
|
100
|
+
async def show_hidden(session):
|
101
|
+
session["show_hidden"] = True
|
102
|
+
return DataGrid(session)
|
103
|
+
|
104
|
+
async def hide_hidden(session):
|
105
|
+
session["show_hidden"] = False
|
106
|
+
return DataGrid(session)
|
107
|
+
|
108
|
+
def compare_action(session, run_ids: str):
|
109
|
+
if "show_hidden" not in session:
|
110
|
+
session["show_hidden"] = False
|
111
|
+
session["datagrid"] = dict()
|
112
|
+
return MainPage(session, swap=True), HttpHeader("HX-Blank-Redirect", f"/compare?run_ids={run_ids}")
|
@@ -0,0 +1,20 @@
|
|
1
|
+
from typing import *
|
2
|
+
from fasthtml.common import *
|
3
|
+
from .utils import format_value
|
4
|
+
def Row(data, run_id, selected: bool, hidden: bool, max_decimals: int, fullscreen: bool):
|
5
|
+
cls = "table-row"
|
6
|
+
if selected:
|
7
|
+
cls += " table-row-selected"
|
8
|
+
|
9
|
+
if hidden:
|
10
|
+
cls += " table-row-hidden"
|
11
|
+
|
12
|
+
return Tr(
|
13
|
+
*[Td(format_value(value, decimals=max_decimals)) for value in data],
|
14
|
+
hx_get=f"/click_row?run_id={run_id}&fullscreen={fullscreen}", # HTMX will GET this URL
|
15
|
+
hx_trigger="click[!event.ctrlKey && !event.metaKey]",
|
16
|
+
hx_target="#experiment-table", # Target DOM element to update
|
17
|
+
hx_swap="innerHTML", # Optional: how to replace content
|
18
|
+
id=f"grid-row-{run_id}",
|
19
|
+
cls=cls,
|
20
|
+
)
|
@@ -0,0 +1,45 @@
|
|
1
|
+
from fasthtml.common import *
|
2
|
+
|
3
|
+
def SortableColumnsJs():
|
4
|
+
src = """
|
5
|
+
import { Sortable } from 'https://cdn.jsdelivr.net/npm/sortablejs/+esm';
|
6
|
+
|
7
|
+
document.addEventListener('DOMContentLoaded', function() {
|
8
|
+
initSortable();
|
9
|
+
});
|
10
|
+
|
11
|
+
function initSortable() {
|
12
|
+
const headerRow = document.getElementById('column-header-row');
|
13
|
+
|
14
|
+
if (!headerRow) return;
|
15
|
+
|
16
|
+
// Initialize SortableJS on the header row
|
17
|
+
new Sortable(headerRow, {
|
18
|
+
animation: 150,
|
19
|
+
ghostClass: 'sortable-ghost',
|
20
|
+
onEnd: function(evt) {
|
21
|
+
// Get the new column order
|
22
|
+
const headers = Array.from(headerRow.children);
|
23
|
+
const columnOrder = headers.map(header =>
|
24
|
+
header.getAttribute('data-col'));
|
25
|
+
|
26
|
+
// Send the new order to the server using htmx as a POST request
|
27
|
+
htmx.ajax('POST', '/reorder_columns', {
|
28
|
+
target: '#experiment-table',
|
29
|
+
swap: 'innerHTML',
|
30
|
+
values: {
|
31
|
+
order: columnOrder.join(',')
|
32
|
+
}
|
33
|
+
});
|
34
|
+
}
|
35
|
+
});
|
36
|
+
}
|
37
|
+
|
38
|
+
// Re-initialize Sortable after HTMX content swaps
|
39
|
+
document.body.addEventListener('htmx:afterSwap', function(evt) {
|
40
|
+
if (evt.detail.target.id === 'experiment-table') {
|
41
|
+
initSortable();
|
42
|
+
}
|
43
|
+
});
|
44
|
+
"""
|
45
|
+
return Script(src, type='module')
|
@@ -0,0 +1,9 @@
|
|
1
|
+
from deepboard.gui.utils import smart_round
|
2
|
+
from datetime import datetime
|
3
|
+
|
4
|
+
def format_value(value, decimals: int = 4):
|
5
|
+
if isinstance(value, datetime):
|
6
|
+
return value.strftime('%Y-%m-%d %H:%M:%S')
|
7
|
+
if isinstance(value, float):
|
8
|
+
return smart_round(value, decimals)
|
9
|
+
return value
|
@@ -0,0 +1,16 @@
|
|
1
|
+
from typing import *
|
2
|
+
from fasthtml.common import *
|
3
|
+
from .datagrid import DataGrid, CompareButton
|
4
|
+
from .right_panel import RightPanel, reset_scalar_session
|
5
|
+
from .main_page import MainPage
|
6
|
+
|
7
|
+
# Choose a row in the datagrid
|
8
|
+
def click_row_handler(session, run_id: int, fullscreen: bool):
|
9
|
+
reset_scalar_session(session)
|
10
|
+
if "datagrid" not in session:
|
11
|
+
session["datagrid"] = dict()
|
12
|
+
session["datagrid"]["selected-rows"] = [run_id]
|
13
|
+
if fullscreen:
|
14
|
+
return MainPage(session, swap=True)
|
15
|
+
else:
|
16
|
+
return DataGrid(session), CompareButton(session, swap=True), RightPanel(session)
|
@@ -0,0 +1,21 @@
|
|
1
|
+
from typing import *
|
2
|
+
from fasthtml.common import *
|
3
|
+
from .datagrid import DataGrid, CompareButton
|
4
|
+
from .right_panel import RightPanel
|
5
|
+
|
6
|
+
def MainPage(session, swap: bool = False, fullscreen: bool = False):
|
7
|
+
return Div(
|
8
|
+
Div(
|
9
|
+
DataGrid(session, wrapincontainer=True, fullscreen=fullscreen),
|
10
|
+
CompareButton(session),
|
11
|
+
Div(hx_target="#container",
|
12
|
+
hx_swap="outerHTML",
|
13
|
+
hx_trigger="keyup[key=='f' || key=='F'] from:body",
|
14
|
+
hx_get=f"/fullscreen?full={'true' if not fullscreen else 'false'}",),
|
15
|
+
cls="table-container"
|
16
|
+
),
|
17
|
+
RightPanel(session, closed = fullscreen),
|
18
|
+
cls='container',
|
19
|
+
id="container",
|
20
|
+
hx_swap_oob="true" if swap else None
|
21
|
+
)
|
@@ -0,0 +1,12 @@
|
|
1
|
+
from .template import RightPanel, fill_panel, reset_scalar_session
|
2
|
+
from .scalars import build_scalar_routes
|
3
|
+
from .run_info import build_info_routes
|
4
|
+
from .images import build_images_routes
|
5
|
+
from .fragments import build_fragment_routes
|
6
|
+
|
7
|
+
def build_right_panel_routes(rt):
|
8
|
+
rt("/fillpanel")(fill_panel)
|
9
|
+
build_images_routes(rt)
|
10
|
+
build_scalar_routes(rt)
|
11
|
+
build_info_routes(rt)
|
12
|
+
build_fragment_routes(rt)
|
@@ -0,0 +1,57 @@
|
|
1
|
+
from typing import *
|
2
|
+
from datetime import datetime, timedelta
|
3
|
+
from fasthtml.common import *
|
4
|
+
from markupsafe import Markup
|
5
|
+
|
6
|
+
def CopyToClipboard(text: str, cls):
|
7
|
+
return Div(
|
8
|
+
Span(text, cls='copy-text' + ' ' + cls),
|
9
|
+
Span(
|
10
|
+
I(cls=f'fas fa-copy copy-icon default-icon {cls}'),
|
11
|
+
I(cls=f'fas fa-check copy-icon check-icon {cls}'),
|
12
|
+
cls='copy-icon-container',
|
13
|
+
),
|
14
|
+
onclick='copyToClipboard(this)',
|
15
|
+
cls='copy-container'
|
16
|
+
)
|
17
|
+
|
18
|
+
def ConfigView(runID: int):
|
19
|
+
from __main__ import rTable
|
20
|
+
|
21
|
+
# Config
|
22
|
+
cfg_text = rTable.load_config(runID)
|
23
|
+
cfg_parts = cfg_text.splitlines()
|
24
|
+
cfg = []
|
25
|
+
for part in cfg_parts:
|
26
|
+
cfg.append(P(Markup(part), cls="config-part"))
|
27
|
+
|
28
|
+
# Cli
|
29
|
+
row = rTable.fetch_experiment(runID)
|
30
|
+
command_line = row[5]
|
31
|
+
if row[4] == "":
|
32
|
+
lines = [P(Markup(""), cls="config-part")]
|
33
|
+
else:
|
34
|
+
cli = {keyvalue.split("=")[0]: "=".join(keyvalue.split("=")[1:]) for keyvalue in row[4].split(" ")}
|
35
|
+
lines = [P(Markup(f"- {key}: {value}"), cls="config-part") for key, value in cli.items()]
|
36
|
+
return Div(
|
37
|
+
Div(
|
38
|
+
H2("Configuration"),
|
39
|
+
Div(
|
40
|
+
*cfg,
|
41
|
+
cls="file-view",
|
42
|
+
)
|
43
|
+
),
|
44
|
+
Div(
|
45
|
+
H2("Cli"),
|
46
|
+
Div(
|
47
|
+
*lines,
|
48
|
+
cls="file-view",
|
49
|
+
),
|
50
|
+
|
51
|
+
Div(
|
52
|
+
CopyToClipboard(command_line, cls=""),
|
53
|
+
cls="file-view",
|
54
|
+
style="margin-top: 2em;"
|
55
|
+
)
|
56
|
+
)
|
57
|
+
)
|
@@ -0,0 +1,133 @@
|
|
1
|
+
from fasthtml.common import *
|
2
|
+
from starlette.responses import Response
|
3
|
+
from typing import *
|
4
|
+
from deepboard.gui.components import Modal, SplitSelector, StatLine, ArtefactGroup
|
5
|
+
|
6
|
+
def _get_fragment_groups(socket, type: Literal["RAW", "HTML"]):
|
7
|
+
if type == "RAW":
|
8
|
+
fragments = socket.read_text()
|
9
|
+
else:
|
10
|
+
fragments = socket.read_fragment()
|
11
|
+
|
12
|
+
index = list({(fragment["step"], fragment["epoch"], fragment["run_rep"], fragment["split"]) for fragment in fragments})
|
13
|
+
|
14
|
+
splits = list({elem[3] for elem in index})
|
15
|
+
|
16
|
+
# Package fragments
|
17
|
+
frag_groups = {}
|
18
|
+
for key in index:
|
19
|
+
cropped_key = key[:-1] # Remove split
|
20
|
+
if cropped_key not in frag_groups:
|
21
|
+
frag_groups[cropped_key] = {split: [] for split in splits}
|
22
|
+
|
23
|
+
for fragment in fragments:
|
24
|
+
key = fragment["step"], fragment["epoch"], fragment["run_rep"]
|
25
|
+
split = fragment["split"]
|
26
|
+
frag_groups[key][split].append(fragment["fragment"])
|
27
|
+
|
28
|
+
# Sort fragments groups by step, and run_rep
|
29
|
+
return dict(sorted(frag_groups.items(), key=lambda x: (x[0][0], x[0][2])))
|
30
|
+
|
31
|
+
|
32
|
+
def TextComponent(text: str):
|
33
|
+
return Div(
|
34
|
+
P(text, cls="fragment-text"),
|
35
|
+
cls="fragment-text-container"
|
36
|
+
)
|
37
|
+
|
38
|
+
def HTMLComponent(html_str: str):
|
39
|
+
# Return whatever is in html_str as a HTML component
|
40
|
+
return NotStr(html_str)
|
41
|
+
|
42
|
+
def FragmentCard(runID: int, step: int, epoch: Optional[int], run_rep: int, frag_type: Literal["RAW", "HTML"],
|
43
|
+
selected: Optional[str] = None):
|
44
|
+
from __main__ import rTable
|
45
|
+
|
46
|
+
socket = rTable.load_run(runID)
|
47
|
+
data = _get_fragment_groups(socket, type=frag_type)
|
48
|
+
|
49
|
+
if (step, epoch, run_rep) not in data:
|
50
|
+
avail_splits = []
|
51
|
+
fragments = []
|
52
|
+
else:
|
53
|
+
fragment_splits = data[(step, epoch, run_rep)]
|
54
|
+
print(fragment_splits)
|
55
|
+
avail_splits = list(fragment_splits.keys())
|
56
|
+
avail_splits.sort()
|
57
|
+
if selected is None:
|
58
|
+
selected = avail_splits[0]
|
59
|
+
fragments = fragment_splits[selected]
|
60
|
+
|
61
|
+
return Div(
|
62
|
+
Div(
|
63
|
+
SplitSelector(runID, avail_splits, selected=selected, step=step, epoch=epoch, run_rep=run_rep,
|
64
|
+
type=frag_type, path="/fragments/change_split"),
|
65
|
+
Div(
|
66
|
+
StatLine("Step", str(step)),
|
67
|
+
StatLine("Epoch", str(epoch) if epoch is not None else "N/A"),
|
68
|
+
StatLine("Run Repetition", str(run_rep)),
|
69
|
+
cls="artefact-stats-column"
|
70
|
+
),
|
71
|
+
cls="artefact-card-header",
|
72
|
+
),
|
73
|
+
ArtefactGroup(*[
|
74
|
+
TextComponent(frag_content) if frag_type == "RAW" else HTMLComponent(frag_content)
|
75
|
+
for frag_content in fragments
|
76
|
+
]),
|
77
|
+
id=f"artefact-card-{step}-{epoch}-{run_rep}",
|
78
|
+
cls="artefact-card",
|
79
|
+
)
|
80
|
+
|
81
|
+
def FragmentTab(session, runID, type: Literal["RAW", "HTML"], swap: bool = False):
|
82
|
+
from __main__ import rTable
|
83
|
+
socket = rTable.load_run(runID)
|
84
|
+
|
85
|
+
fragment_groups = _get_fragment_groups(socket, type=type)
|
86
|
+
return Div(
|
87
|
+
*[
|
88
|
+
FragmentCard(runID, step, epoch, run_rep, frag_type=type)
|
89
|
+
for step, epoch, run_rep in fragment_groups.keys()
|
90
|
+
],
|
91
|
+
style="display; flex; flex-direction: column; align-items: center; justify-content: center;",
|
92
|
+
id="fragment-tab",
|
93
|
+
hx_swap_oob="true" if swap else None,
|
94
|
+
)
|
95
|
+
|
96
|
+
|
97
|
+
def fragment_enable(runID, type: Literal["RAW", "HTML"]):
|
98
|
+
"""
|
99
|
+
Check if some fragments/text are logged and available for the runID. If not, we consider disable it.
|
100
|
+
:param runID: The runID to check.
|
101
|
+
:return: True if scalars are available, False otherwise.
|
102
|
+
"""
|
103
|
+
from __main__ import rTable
|
104
|
+
socket = rTable.load_run(runID)
|
105
|
+
if type == "RAW":
|
106
|
+
return len(socket.read_text()) > 0
|
107
|
+
else:
|
108
|
+
return len(socket.read_fragment()) > 0
|
109
|
+
|
110
|
+
# routes
|
111
|
+
def build_fragment_routes(rt):
|
112
|
+
rt("/fragments/change_split")(change_split)
|
113
|
+
|
114
|
+
|
115
|
+
def change_split(session, runID: int, step: int, epoch: Optional[int], run_rep: int, split_select: str, type: str):
|
116
|
+
"""
|
117
|
+
Change the split for the fragment.
|
118
|
+
:param session: The session object.
|
119
|
+
:param step: The step of the fragment.
|
120
|
+
:param epoch: The epoch of the fragment.
|
121
|
+
:param run_rep: The run repetition of the fragments.
|
122
|
+
:param split: The split to change to.
|
123
|
+
:return: The updated fragment card HTML.
|
124
|
+
"""
|
125
|
+
return FragmentCard(
|
126
|
+
runID,
|
127
|
+
step,
|
128
|
+
epoch,
|
129
|
+
run_rep,
|
130
|
+
frag_type=type,
|
131
|
+
selected=split_select,
|
132
|
+
)
|
133
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
from typing import *
|
2
|
+
from datetime import datetime, timedelta
|
3
|
+
from fasthtml.common import *
|
4
|
+
from markupsafe import Markup
|
5
|
+
|
6
|
+
def HParamsView(runID: int):
|
7
|
+
from __main__ import rTable
|
8
|
+
socket = rTable.load_run(runID)
|
9
|
+
hparams = socket.get_hparams()
|
10
|
+
return Div(
|
11
|
+
Table(
|
12
|
+
Tr(
|
13
|
+
Th('Parameter'),
|
14
|
+
Th('Value'),
|
15
|
+
),
|
16
|
+
*[
|
17
|
+
Tr(
|
18
|
+
Td(key),
|
19
|
+
Td(value),
|
20
|
+
)
|
21
|
+
for key, value in hparams.items()
|
22
|
+
],
|
23
|
+
cls="hparams-table",
|
24
|
+
)
|
25
|
+
)
|