diff --git a/src/yolo_webui/app.py b/src/yolo_webui/app.py index 9b198ad..ae5454f 100755 --- a/src/yolo_webui/app.py +++ b/src/yolo_webui/app.py @@ -28,6 +28,17 @@ logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(me logger = logging.getLogger("yolo_webui") SESSION_NAME_PATTERN = re.compile(r"^[A-Za-z0-9_-]{1,64}$") +try: + from ultralytics import settings as _ultralytics_settings + _workspace_root = Path.cwd().resolve() + _ultralytics_settings.update({ + "runs_dir": str((_workspace_root / "runs").resolve()), + "datasets_dir": str((_workspace_root / "datasets").resolve()), + "weights_dir": str((_workspace_root / "models").resolve()), + }) +except Exception as _exc: + logger.debug(f"Ultralytics settings init skipped: {_exc}") + @dataclass class LiveState: diff --git a/src/yolo_webui/config.py b/src/yolo_webui/config.py index 4476028..cfa4a50 100755 --- a/src/yolo_webui/config.py +++ b/src/yolo_webui/config.py @@ -364,6 +364,10 @@ class TrainingConfig: def train_kwargs(self) -> dict[str, str | int | float | bool]: """Convert the form values to arguments accepted by YOLO.train().""" + project_path = Path(self.project.strip() or "runs/train") + if not project_path.is_absolute(): + project_path = (Path.cwd() / project_path).resolve() + values: dict[str, str | int | float | bool] = { "data": self.dataset.strip(), "epochs": self.epochs, @@ -371,7 +375,7 @@ class TrainingConfig: "batch": self.batch_size, "workers": self.workers, "patience": self.patience, - "project": self.project.strip() or "runs/train", + "project": str(project_path), # Enable verbose output so users see active progress and losses in the log console. "verbose": True, } diff --git a/src/yolo_webui/static/app.js b/src/yolo_webui/static/app.js index dc97f64..9251863 100755 --- a/src/yolo_webui/static/app.js +++ b/src/yolo_webui/static/app.js @@ -125,10 +125,6 @@ document.addEventListener('DOMContentLoaded', () => { const autoscrollCheck = document.getElementById('autoscroll'); const clearLogBtn = document.getElementById('clear-log-btn'); - // Chart - const ctx = document.getElementById('metricsChart').getContext('2d'); - let metricsChart = null; - // State variables let trainingTimer = null; let secondsElapsed = 0; @@ -268,78 +264,6 @@ document.addEventListener('DOMContentLoaded', () => { logContainer.innerHTML = ''; }); - // --- Chart.js Integration --- - function initChart(datasets = []) { - if (metricsChart) { - metricsChart.destroy(); - } - - metricsChart = new Chart(ctx, { - type: 'line', - data: { - labels: [], - datasets: datasets - }, - options: { - responsive: true, - maintainAspectRatio: false, - scales: { - x: { - title: { display: true, text: 'Эпоха', color: '#a1a1aa' }, - grid: { color: '#27272a' }, - ticks: { color: '#a1a1aa' } - }, - y: { - title: { display: true, text: 'Значение', color: '#a1a1aa' }, - grid: { color: '#27272a' }, - ticks: { color: '#a1a1aa' } - } - }, - plugins: { - legend: { - labels: { color: '#f4f4f5', font: { family: 'Outfit' } } - } - } - } - }); - } - - function updateChart(epoch, metrics) { - if (!metricsChart) { - initChart(); - } - - let labelIndex = metricsChart.data.labels.indexOf(epoch); - if (labelIndex === -1) { - metricsChart.data.labels.push(epoch); - labelIndex = metricsChart.data.labels.length - 1; - metricsChart.data.datasets.forEach(dataset => dataset.data.push(null)); - } - - const colors = ['#f97316', '#10b981', '#3b82f6', '#eab308', '#a855f7']; - Object.entries(metrics).forEach(([key, value]) => { - if (key === 'epoch') return; - - let dataset = metricsChart.data.datasets.find(item => item.label === key); - if (!dataset) { - const color = colors[metricsChart.data.datasets.length % colors.length]; - dataset = { - label: key, - data: Array(metricsChart.data.labels.length).fill(null), - borderColor: color, - backgroundColor: color + '22', - tension: 0.15, - fill: false - }; - metricsChart.data.datasets.push(dataset); - } - - dataset.data[labelIndex] = value; - }); - - metricsChart.update(); - } - // --- Timer UI --- function startTimer() { stopTimer(); @@ -427,14 +351,6 @@ document.addEventListener('DOMContentLoaded', () => { addLogLine(msg, level); }); - // Draw initial chart points - initChart(); - if (Array.isArray(data.metrics) && data.metrics.length > 0) { - data.metrics.forEach(m => { - updateChart(m.epoch, m); - }); - } - // Sync progress if (data.status === 'training' || data.status === 'stopping') { updateProgress(data.epoch, data.total_epochs); @@ -468,9 +384,6 @@ document.addEventListener('DOMContentLoaded', () => { } } else if (data.type === 'progress') { updateProgress(data.epoch, data.total_epochs, data.message); - if (data.metrics) { - updateChart(data.epoch, data.metrics); - } } }; } @@ -496,7 +409,6 @@ document.addEventListener('DOMContentLoaded', () => { startBtn.disabled = true; stopBtn.disabled = false; startTimer(); - initChart(); break; case 'training': statusTitle.textContent = 'ОБУЧЕНИЕ'; @@ -1337,6 +1249,5 @@ document.addEventListener('DOMContentLoaded', () => { loadSessionsList(); connectWebSocket(); connectExportWebSocket(); - initChart(); }); }); diff --git a/src/yolo_webui/static/index.html b/src/yolo_webui/static/index.html index 6bf2507..d99981e 100755 --- a/src/yolo_webui/static/index.html +++ b/src/yolo_webui/static/index.html @@ -8,8 +8,6 @@ - -
@@ -377,17 +375,6 @@ - -