flashstudio 0.0.1__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.
Potentially problematic release.
This version of flashstudio might be problematic. Click here for more details.
- flashstudio/__init__.py +5 -0
- flashstudio/app.py +194 -0
- flashstudio/cli.py +18 -0
- flashstudio/components/__init__.py +0 -0
- flashstudio/components/project_manager.py +490 -0
- flashstudio/components/sidebar.py +87 -0
- flashstudio/components/styles.py +346 -0
- flashstudio/components/wizard.py +45 -0
- flashstudio/components/zone_drawer/__init__.py +177 -0
- flashstudio/constants.py +245 -0
- flashstudio/core/__init__.py +3 -0
- flashstudio/core/constants.py +3 -0
- flashstudio/launcher.py +288 -0
- flashstudio/pages/__init__.py +8 -0
- flashstudio/pages/dashboard/__init__.py +3 -0
- flashstudio/pages/dashboard/_common.py +10 -0
- flashstudio/pages/dashboard/overview/__init__.py +3 -0
- flashstudio/pages/dashboard/overview/metrics.py +33 -0
- flashstudio/pages/dashboard/overview/pipeline_status.py +35 -0
- flashstudio/pages/dashboard/overview/project_banner.py +23 -0
- flashstudio/pages/dashboard/overview/quick_actions.py +28 -0
- flashstudio/pages/dashboard/overview/recent_runs.py +99 -0
- flashstudio/pages/dashboard/overview/tab.py +35 -0
- flashstudio/pages/dashboard/page.py +17 -0
- flashstudio/pages/data/__init__.py +3 -0
- flashstudio/pages/data/_common.py +107 -0
- flashstudio/pages/data/download/__init__.py +3 -0
- flashstudio/pages/data/download/tab.py +75 -0
- flashstudio/pages/data/helpers.py +338 -0
- flashstudio/pages/data/page.py +50 -0
- flashstudio/pages/data/preview/__init__.py +3 -0
- flashstudio/pages/data/preview/tab.py +139 -0
- flashstudio/pages/data/upload/__init__.py +3 -0
- flashstudio/pages/data/upload/tab.py +156 -0
- flashstudio/pages/data/verify/__init__.py +3 -0
- flashstudio/pages/data/verify/tab.py +108 -0
- flashstudio/pages/export/__init__.py +3 -0
- flashstudio/pages/export/page.py +54 -0
- flashstudio/pages/export/weights/__init__.py +4 -0
- flashstudio/pages/export/weights/exporter.py +60 -0
- flashstudio/pages/export/weights/settings.py +86 -0
- flashstudio/pages/inference/__init__.py +3 -0
- flashstudio/pages/inference/_common.py +76 -0
- flashstudio/pages/inference/data/__init__.py +3 -0
- flashstudio/pages/inference/data/tab.py +121 -0
- flashstudio/pages/inference/model/__init__.py +3 -0
- flashstudio/pages/inference/model/tab.py +62 -0
- flashstudio/pages/inference/page.py +42 -0
- flashstudio/pages/inference/run/__init__.py +3 -0
- flashstudio/pages/inference/run/detection.py +133 -0
- flashstudio/pages/inference/run/tab.py +161 -0
- flashstudio/pages/inference/run/video.py +195 -0
- flashstudio/pages/inference/solution/__init__.py +3 -0
- flashstudio/pages/inference/solution/tab.py +121 -0
- flashstudio/pages/model/__init__.py +3 -0
- flashstudio/pages/model/_common.py +3 -0
- flashstudio/pages/model/advanced/__init__.py +3 -0
- flashstudio/pages/model/advanced/tab.py +54 -0
- flashstudio/pages/model/architecture/__init__.py +3 -0
- flashstudio/pages/model/architecture/tab.py +90 -0
- flashstudio/pages/model/augment/__init__.py +3 -0
- flashstudio/pages/model/augment/tab.py +18 -0
- flashstudio/pages/model/hyperparams/__init__.py +4 -0
- flashstudio/pages/model/hyperparams/tab.py +89 -0
- flashstudio/pages/model/page.py +30 -0
- flashstudio/pages/model/utils/__init__.py +3 -0
- flashstudio/pages/model/utils/config.py +27 -0
- flashstudio/pages/training/__init__.py +3 -0
- flashstudio/pages/training/_common.py +24 -0
- flashstudio/pages/training/launch/__init__.py +3 -0
- flashstudio/pages/training/launch/controls.py +84 -0
- flashstudio/pages/training/launch/dialogs.py +247 -0
- flashstudio/pages/training/launch/preflight.py +77 -0
- flashstudio/pages/training/launch/runner.py +440 -0
- flashstudio/pages/training/launch/tab.py +134 -0
- flashstudio/pages/training/monitor/__init__.py +3 -0
- flashstudio/pages/training/monitor/checkpoints.py +96 -0
- flashstudio/pages/training/monitor/curves.py +113 -0
- flashstudio/pages/training/monitor/dashboard.py +129 -0
- flashstudio/pages/training/monitor/gt_verification.py +122 -0
- flashstudio/pages/training/monitor/log_viewer.py +43 -0
- flashstudio/pages/training/monitor/parsers.py +253 -0
- flashstudio/pages/training/monitor/run_meta.py +165 -0
- flashstudio/pages/training/monitor/tab.py +142 -0
- flashstudio/pages/training/monitor/visualizations.py +52 -0
- flashstudio/pages/training/page.py +134 -0
- flashstudio/utils/__init__.py +152 -0
- flashstudio/utils/config.py +104 -0
- flashstudio/utils/device.py +67 -0
- flashstudio/utils/filesystem.py +67 -0
- flashstudio/utils/jobs.py +95 -0
- flashstudio/utils/training_hooks.py +266 -0
- flashstudio-0.0.1.dist-info/METADATA +107 -0
- flashstudio-0.0.1.dist-info/RECORD +97 -0
- flashstudio-0.0.1.dist-info/WHEEL +5 -0
- flashstudio-0.0.1.dist-info/entry_points.txt +2 -0
- flashstudio-0.0.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""Dashboard — quick action buttons section."""
|
|
2
|
+
|
|
3
|
+
import streamlit as st
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def render_quick_actions():
|
|
7
|
+
ac1, ac2, ac3 = st.columns(3)
|
|
8
|
+
with ac1:
|
|
9
|
+
if st.button("Upload Data", use_container_width=True, key="dash_goto_data"):
|
|
10
|
+
st.session_state["current_step"] = 1
|
|
11
|
+
st.rerun()
|
|
12
|
+
if st.button("Configure Model", use_container_width=True, key="dash_goto_model"):
|
|
13
|
+
st.session_state["current_step"] = 2
|
|
14
|
+
st.rerun()
|
|
15
|
+
with ac2:
|
|
16
|
+
if st.button("Start Training", use_container_width=True, type="primary", key="dash_goto_train"):
|
|
17
|
+
st.session_state["current_step"] = 3
|
|
18
|
+
st.rerun()
|
|
19
|
+
if st.button("Export Model", use_container_width=True, key="dash_goto_export"):
|
|
20
|
+
st.session_state["current_step"] = 4
|
|
21
|
+
st.rerun()
|
|
22
|
+
with ac3:
|
|
23
|
+
if st.button("Run Inference", use_container_width=True, key="dash_goto_infer"):
|
|
24
|
+
st.session_state["current_step"] = 5
|
|
25
|
+
st.rerun()
|
|
26
|
+
if st.button("Projects", use_container_width=True, key="dash_goto_proj"):
|
|
27
|
+
st.session_state["show_project_manager"] = True
|
|
28
|
+
st.rerun()
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"""Dashboard — recent runs section."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import re
|
|
5
|
+
import time
|
|
6
|
+
import glob as glob_module
|
|
7
|
+
import streamlit as st
|
|
8
|
+
from flashstudio.pages.dashboard._common import (
|
|
9
|
+
DEFAULT_SAVE_DIR, MAX_DISPLAY_RUNS,
|
|
10
|
+
CKPT_BEST, CKPT_BEST_INFERENCE, CKPT_FINAL_INFERENCE,
|
|
11
|
+
CKPT_FINAL_FP16, TRAINING_LOG_CSV,
|
|
12
|
+
COLOR_SUCCESS, COLOR_TEXT_PRIMARY, COLOR_TEXT_SECONDARY,
|
|
13
|
+
COLOR_TEXT_MUTED, COLOR_BORDER,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def render_recent_runs():
|
|
18
|
+
from flashstudio.components.project_manager import get_active_project, get_project_dir
|
|
19
|
+
|
|
20
|
+
user_save_dir = st.session_state.get("save_dir", "")
|
|
21
|
+
|
|
22
|
+
candidates = []
|
|
23
|
+
active_proj = get_active_project()
|
|
24
|
+
if active_proj:
|
|
25
|
+
candidates.append(os.path.join(get_project_dir(active_proj["id"]), "runs"))
|
|
26
|
+
if user_save_dir and user_save_dir != DEFAULT_SAVE_DIR:
|
|
27
|
+
candidates.append(user_save_dir)
|
|
28
|
+
candidates.append(DEFAULT_SAVE_DIR)
|
|
29
|
+
ws = None
|
|
30
|
+
for c in candidates:
|
|
31
|
+
c = os.path.abspath(c)
|
|
32
|
+
if os.path.isdir(c):
|
|
33
|
+
ws = c
|
|
34
|
+
break
|
|
35
|
+
|
|
36
|
+
if not ws:
|
|
37
|
+
st.caption("No workspace found. Start training to create runs.")
|
|
38
|
+
return
|
|
39
|
+
|
|
40
|
+
dirs = sorted(
|
|
41
|
+
[d for d in os.listdir(ws) if os.path.isdir(os.path.join(ws, d))],
|
|
42
|
+
key=lambda d: os.path.getmtime(os.path.join(ws, d)), reverse=True,
|
|
43
|
+
)[:MAX_DISPLAY_RUNS]
|
|
44
|
+
|
|
45
|
+
if not dirs:
|
|
46
|
+
st.caption("No runs yet. Go to Training to start your first run.")
|
|
47
|
+
return
|
|
48
|
+
|
|
49
|
+
for name in dirs:
|
|
50
|
+
rd = os.path.join(ws, name)
|
|
51
|
+
has_best = (os.path.isfile(os.path.join(rd, CKPT_BEST))
|
|
52
|
+
or os.path.isfile(os.path.join(rd, CKPT_BEST_INFERENCE)))
|
|
53
|
+
has_final = (os.path.isfile(os.path.join(rd, CKPT_FINAL_INFERENCE))
|
|
54
|
+
or os.path.isfile(os.path.join(rd, CKPT_FINAL_FP16)))
|
|
55
|
+
status = "Done" if (has_best or has_final) else "\u2014"
|
|
56
|
+
info = ""
|
|
57
|
+
csv_path = os.path.join(rd, TRAINING_LOG_CSV)
|
|
58
|
+
if os.path.isfile(csv_path):
|
|
59
|
+
try:
|
|
60
|
+
import csv as _csv
|
|
61
|
+
with open(csv_path, "r") as _f:
|
|
62
|
+
rows = list(_csv.DictReader(_f))
|
|
63
|
+
if rows:
|
|
64
|
+
vals = [float(r.get("mAP@0.5", 0)) for r in rows if r.get("mAP@0.5", "").strip()]
|
|
65
|
+
if vals:
|
|
66
|
+
info = f"mAP {max(vals):.3f}"
|
|
67
|
+
except Exception:
|
|
68
|
+
pass
|
|
69
|
+
if not info:
|
|
70
|
+
from flashstudio.constants import TRAINING_LOG_GLOB
|
|
71
|
+
log_files = glob_module.glob(os.path.join(rd, TRAINING_LOG_GLOB))
|
|
72
|
+
if log_files:
|
|
73
|
+
try:
|
|
74
|
+
best_log = max(log_files, key=lambda p: os.path.getsize(p))
|
|
75
|
+
with open(best_log, "r", encoding="utf-8", errors="replace") as _f:
|
|
76
|
+
for _ln in _f.readlines()[-10:]:
|
|
77
|
+
bm = re.search(r"Best mAP@0\.5:\s*([\d.]+)", _ln)
|
|
78
|
+
if bm:
|
|
79
|
+
info = f"mAP {bm.group(1)}"
|
|
80
|
+
except OSError:
|
|
81
|
+
pass
|
|
82
|
+
|
|
83
|
+
mtime = os.path.getmtime(rd)
|
|
84
|
+
date_str = time.strftime("%b %d, %H:%M", time.localtime(mtime))
|
|
85
|
+
status_color = COLOR_SUCCESS if (has_best or has_final) else COLOR_TEXT_MUTED
|
|
86
|
+
|
|
87
|
+
st.markdown(
|
|
88
|
+
f'<div style="display:flex;justify-content:space-between;align-items:center;'
|
|
89
|
+
f'font-size:0.85rem;padding:0.4rem 0;border-bottom:1px solid {COLOR_BORDER};">'
|
|
90
|
+
f'<div>'
|
|
91
|
+
f'<span style="font-weight:600;color:{COLOR_TEXT_PRIMARY};">{name[:25]}</span>'
|
|
92
|
+
f'<span style="color:{COLOR_TEXT_MUTED};font-size:0.75rem;margin-left:0.5rem;">{date_str}</span>'
|
|
93
|
+
f'</div>'
|
|
94
|
+
f'<div style="display:flex;gap:0.8rem;align-items:center;">'
|
|
95
|
+
f'<span style="color:{COLOR_TEXT_SECONDARY};">{info}</span>'
|
|
96
|
+
f'<span style="color:{status_color};font-weight:600;">{status}</span>'
|
|
97
|
+
f'</div></div>',
|
|
98
|
+
unsafe_allow_html=True,
|
|
99
|
+
)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""Dashboard overview — orchestrates all overview sections."""
|
|
2
|
+
|
|
3
|
+
import streamlit as st
|
|
4
|
+
from flashstudio.pages.dashboard.overview.project_banner import render_project_banner
|
|
5
|
+
from flashstudio.pages.dashboard.overview.metrics import render_metrics
|
|
6
|
+
from flashstudio.pages.dashboard.overview.pipeline_status import render_pipeline_status
|
|
7
|
+
from flashstudio.pages.dashboard.overview.quick_actions import render_quick_actions
|
|
8
|
+
from flashstudio.pages.dashboard.overview.recent_runs import render_recent_runs
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def render_overview(project, stats):
|
|
12
|
+
from flashstudio.utils.device import get_gpu_info
|
|
13
|
+
|
|
14
|
+
gpu = get_gpu_info()
|
|
15
|
+
|
|
16
|
+
if project:
|
|
17
|
+
render_project_banner(project)
|
|
18
|
+
|
|
19
|
+
render_metrics(gpu, stats)
|
|
20
|
+
|
|
21
|
+
left, right = st.columns(2)
|
|
22
|
+
|
|
23
|
+
with left:
|
|
24
|
+
with st.container(border=True):
|
|
25
|
+
st.markdown("#### Pipeline Status")
|
|
26
|
+
render_pipeline_status()
|
|
27
|
+
|
|
28
|
+
with right:
|
|
29
|
+
with st.container(border=True):
|
|
30
|
+
st.markdown("#### Quick Actions")
|
|
31
|
+
render_quick_actions()
|
|
32
|
+
|
|
33
|
+
with st.container(border=True):
|
|
34
|
+
st.markdown("#### Recent Runs")
|
|
35
|
+
render_recent_runs()
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""FlashStudio — Dashboard."""
|
|
2
|
+
|
|
3
|
+
from flashstudio.components.styles import render_page_header
|
|
4
|
+
from flashstudio.pages.dashboard.overview.tab import render_overview
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def render_dashboard():
|
|
8
|
+
from flashstudio.components.project_manager import get_active_project, get_project_stats
|
|
9
|
+
from flashstudio.utils import show_flashes
|
|
10
|
+
|
|
11
|
+
render_page_header("", "Dashboard")
|
|
12
|
+
show_flashes()
|
|
13
|
+
|
|
14
|
+
project = get_active_project()
|
|
15
|
+
stats = get_project_stats(project["id"]) if project else None
|
|
16
|
+
|
|
17
|
+
render_overview(project, stats)
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"""Shared helpers and constants for the data page."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import json
|
|
5
|
+
import streamlit as st
|
|
6
|
+
|
|
7
|
+
from flashstudio.constants import (
|
|
8
|
+
DEFAULT_DATA_DIR, NETWORK_CHECK_URL, NETWORK_CHECK_TIMEOUT,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
try:
|
|
12
|
+
from flashdet import download_dataset, list_datasets # noqa: F401
|
|
13
|
+
from flashdet.data import ( # noqa: F401
|
|
14
|
+
convert_dataset, detect_dataset_format,
|
|
15
|
+
verify_dataset, summarize_coco_root,
|
|
16
|
+
)
|
|
17
|
+
_HAS_FLASHDET = True
|
|
18
|
+
except ImportError:
|
|
19
|
+
_HAS_FLASHDET = False
|
|
20
|
+
|
|
21
|
+
_FLASHDET_INSTALL_MSG = "FlashDet required — install with: `pip install flashdet`"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _extract_classes_from_coco_json(ann_path: str) -> list[str]:
|
|
25
|
+
"""Read class names from a COCO-format annotation JSON file."""
|
|
26
|
+
try:
|
|
27
|
+
with open(ann_path, encoding="utf-8") as f:
|
|
28
|
+
data = json.load(f)
|
|
29
|
+
cats = data.get("categories", [])
|
|
30
|
+
if not cats:
|
|
31
|
+
return []
|
|
32
|
+
sorted_cats = sorted(cats, key=lambda c: c.get("id", 0))
|
|
33
|
+
return [c["name"] for c in sorted_cats]
|
|
34
|
+
except (OSError, json.JSONDecodeError, KeyError, TypeError):
|
|
35
|
+
return []
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _auto_detect_classes():
|
|
39
|
+
"""Try to auto-detect classes from the loaded dataset annotation."""
|
|
40
|
+
train_path = st.session_state.get("train_img_path", "")
|
|
41
|
+
if not train_path or not os.path.isdir(train_path):
|
|
42
|
+
return []
|
|
43
|
+
|
|
44
|
+
ann_file = os.path.join(train_path, "_annotations.coco.json")
|
|
45
|
+
if not os.path.isfile(ann_file):
|
|
46
|
+
json_files = [f for f in os.listdir(train_path) if f.endswith(".json")]
|
|
47
|
+
if json_files:
|
|
48
|
+
ann_file = os.path.join(train_path, json_files[0])
|
|
49
|
+
else:
|
|
50
|
+
return []
|
|
51
|
+
|
|
52
|
+
return _extract_classes_from_coco_json(ann_file)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _get_native_datasets():
|
|
56
|
+
if not _HAS_FLASHDET:
|
|
57
|
+
return []
|
|
58
|
+
try:
|
|
59
|
+
return list_datasets()
|
|
60
|
+
except Exception:
|
|
61
|
+
return []
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _check_network() -> bool:
|
|
65
|
+
import urllib.request
|
|
66
|
+
import urllib.error
|
|
67
|
+
try:
|
|
68
|
+
urllib.request.urlopen(NETWORK_CHECK_URL, timeout=NETWORK_CHECK_TIMEOUT)
|
|
69
|
+
return True
|
|
70
|
+
except (urllib.error.URLError, OSError):
|
|
71
|
+
return False
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _dataset_already_downloaded(dataset_id: str, output_dir: str | None = None) -> str | None:
|
|
75
|
+
if output_dir is None:
|
|
76
|
+
output_dir = os.path.join(DEFAULT_DATA_DIR, dataset_id)
|
|
77
|
+
if not os.path.isdir(output_dir):
|
|
78
|
+
return None
|
|
79
|
+
t = os.path.join(output_dir, "train")
|
|
80
|
+
v = os.path.join(output_dir, "valid")
|
|
81
|
+
if not os.path.isdir(v):
|
|
82
|
+
v = os.path.join(output_dir, "val")
|
|
83
|
+
if os.path.isdir(t) and os.path.isdir(v) and os.listdir(t) and os.listdir(v):
|
|
84
|
+
return output_dir
|
|
85
|
+
return None
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
EXTERNAL_DATASETS = [
|
|
89
|
+
{"name": "COCO128", "imgs": 128, "cls": 80, "sz": "7MB", "fmt": "COCO", "url": "https://github.com/ultralytics/yolov5/releases/download/v1.0/coco128.zip"},
|
|
90
|
+
{"name": "Objects365", "imgs": 5000, "cls": 365, "sz": "~2GB", "fmt": "COCO", "url": "https://dorc.ks3-cn-beijing.ksyun.com/data-set/2020Objects365%E6%95%B0%E6%8D%AE%E9%9B%86/val/zhiyuan_objv2_val.json"},
|
|
91
|
+
{"name": "GlobalWheat", "imgs": 4700, "cls": 1, "sz": "~3GB", "fmt": "COCO", "url": "https://zenodo.org/record/4298502"},
|
|
92
|
+
{"name": "VisDrone", "imgs": 6471, "cls": 10, "sz": "~2GB", "fmt": "Custom", "url": "https://github.com/VisDrone/VisDrone-Dataset"},
|
|
93
|
+
{"name": "SKU-110K", "imgs": 11762, "cls": 1, "sz": "~3GB", "fmt": "CSV", "url": "https://github.com/eg4000/SKU110K_CVPR19"},
|
|
94
|
+
{"name": "WIDER Face", "imgs": 32203, "cls": 1, "sz": "~1.5GB", "fmt": "Custom", "url": "http://shuoyang1213.me/WIDERFACE/"},
|
|
95
|
+
{"name": "Cityscapes", "imgs": 5000, "cls": 30, "sz": "~11GB", "fmt": "Custom", "url": "https://www.cityscapes-dataset.com/"},
|
|
96
|
+
{"name": "BDD100K", "imgs": 100000, "cls": 10, "sz": "~6GB", "fmt": "Custom", "url": "https://bdd-data.berkeley.edu/"},
|
|
97
|
+
{"name": "KITTI", "imgs": 7481, "cls": 3, "sz": "~12GB", "fmt": "Custom", "url": "http://www.cvlibs.net/datasets/kitti/eval_object.php"},
|
|
98
|
+
{"name": "xView", "imgs": 1400, "cls": 60, "sz": "~4GB", "fmt": "GeoJSON", "url": "http://xviewdataset.org/"},
|
|
99
|
+
{"name": "OpenImages V7", "imgs": 1900000, "cls": 600, "sz": "~500GB", "fmt": "CSV", "url": "https://storage.googleapis.com/openimages/web/index.html"},
|
|
100
|
+
{"name": "LVIS v1", "imgs": 164000, "cls": 1203, "sz": "~20GB", "fmt": "COCO", "url": "https://www.lvisdataset.org/"},
|
|
101
|
+
]
|
|
102
|
+
|
|
103
|
+
QUICK_START = [
|
|
104
|
+
{"id": "sample", "name": "FlashDet Sample", "imgs": 50, "cls": 80, "sz": "~1GB"},
|
|
105
|
+
{"id": "coco2017-val", "name": "COCO 2017 Val", "imgs": 5000, "cls": 80, "sz": "~1GB"},
|
|
106
|
+
{"id": "voc2007", "name": "VOC 2007", "imgs": 9963, "cls": 20, "sz": "~900MB"},
|
|
107
|
+
]
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""Download tab — Quick Start, Native, and External dataset sections."""
|
|
2
|
+
|
|
3
|
+
import streamlit as st
|
|
4
|
+
|
|
5
|
+
from flashstudio.constants import INFER_NUM_CLASSES
|
|
6
|
+
from flashstudio.pages.data._common import (
|
|
7
|
+
_get_native_datasets, _dataset_already_downloaded,
|
|
8
|
+
EXTERNAL_DATASETS, QUICK_START,
|
|
9
|
+
)
|
|
10
|
+
from flashstudio.pages.data.helpers import (
|
|
11
|
+
_use_existing, _run_flashdet_download, _run_external_download,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _render_download():
|
|
16
|
+
# Quick start — compact single row each
|
|
17
|
+
st.markdown("#### Quick Start")
|
|
18
|
+
for idx, ds in enumerate(QUICK_START):
|
|
19
|
+
did = ds["id"]
|
|
20
|
+
existing = _dataset_already_downloaded(did)
|
|
21
|
+
c1, c2 = st.columns([5, 1])
|
|
22
|
+
with c1:
|
|
23
|
+
st.markdown(
|
|
24
|
+
f'<div style="font-size:0.88rem;"><b>{ds["name"]}</b> · '
|
|
25
|
+
f'{ds["imgs"]} imgs · {ds["cls"]} cls · {ds["sz"]}</div>',
|
|
26
|
+
unsafe_allow_html=True,
|
|
27
|
+
)
|
|
28
|
+
with c2:
|
|
29
|
+
label = "Use" if existing else "Get"
|
|
30
|
+
if st.button(label, key=f"qs_{idx}", use_container_width=True, type="primary"):
|
|
31
|
+
if existing:
|
|
32
|
+
_use_existing(existing, ds)
|
|
33
|
+
else:
|
|
34
|
+
st.session_state.update({"dataset_name": ds["name"], "dataset_classes": ds["cls"], "dataset_id": did})
|
|
35
|
+
_run_flashdet_download(did)
|
|
36
|
+
|
|
37
|
+
st.divider()
|
|
38
|
+
|
|
39
|
+
# Native datasets
|
|
40
|
+
native = _get_native_datasets()
|
|
41
|
+
if native:
|
|
42
|
+
with st.expander(f"FlashDet Native ({len(native)} datasets)", expanded=False):
|
|
43
|
+
for i, ds in enumerate(native):
|
|
44
|
+
did = ds.get("id", ds.get("name", "").lower().replace(" ", ""))
|
|
45
|
+
existing = _dataset_already_downloaded(did)
|
|
46
|
+
c1, c2 = st.columns([5, 1])
|
|
47
|
+
with c1:
|
|
48
|
+
st.caption(f"**{ds.get('name', did)}** · {ds.get('classes', '?')} cls")
|
|
49
|
+
with c2:
|
|
50
|
+
if st.button("Use" if existing else "Get", key=f"nat_{i}", use_container_width=True):
|
|
51
|
+
if existing:
|
|
52
|
+
_use_existing(existing, ds)
|
|
53
|
+
else:
|
|
54
|
+
st.session_state.update({"dataset_name": ds.get("name", did), "dataset_id": did, "dataset_classes": ds.get("classes", INFER_NUM_CLASSES)})
|
|
55
|
+
_run_flashdet_download(did)
|
|
56
|
+
|
|
57
|
+
# External
|
|
58
|
+
with st.expander(f"External Datasets ({len(EXTERNAL_DATASETS)})", expanded=False):
|
|
59
|
+
for i, ds in enumerate(EXTERNAL_DATASETS):
|
|
60
|
+
c1, c2 = st.columns([5, 1])
|
|
61
|
+
with c1:
|
|
62
|
+
st.markdown(
|
|
63
|
+
f'<div style="font-size:0.88rem;"><b>{ds["name"]}</b> · '
|
|
64
|
+
f'{ds["imgs"]} · {ds["cls"]} cls · {ds["sz"]} · {ds["fmt"]}</div>',
|
|
65
|
+
unsafe_allow_html=True,
|
|
66
|
+
)
|
|
67
|
+
with c2:
|
|
68
|
+
url = ds.get("url", "")
|
|
69
|
+
is_manual = not url or "VisDrone" in url
|
|
70
|
+
if st.button("Link" if is_manual else "Get", key=f"ext_{i}", use_container_width=True):
|
|
71
|
+
if is_manual:
|
|
72
|
+
st.info(f"Manual: [{url}]({url})")
|
|
73
|
+
else:
|
|
74
|
+
st.session_state.update({"dataset_name": ds["name"], "dataset_classes": ds["cls"]})
|
|
75
|
+
_run_external_download(ds)
|