diff --git a/README.md b/README.md index 131e5d6..f1c2eb7 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,8 @@ without changing the original training scripts. Starting any web job or dataset YOLO shortcut automatically opens its live log; the SSE stream resumes from the current log size after the initial tail so existing lines are not duplicated in the panel. +The selected-job panel also shows reproducibility diagnostics: command, cwd, +PID, exit code, log size, error text, and the exact task params submitted. The task builder also reads `GET /api/system/gpus` and lets an operator choose CPU or one or more GPUs before launch. Selected GPUs are passed to the backend as `gpus`, exported as `CUDA_VISIBLE_DEVICES`, and reflected into YOLO/visual diff --git a/backend/app/agents/evaluation_agent.py b/backend/app/agents/evaluation_agent.py index cf3a459..3c7d06a 100644 --- a/backend/app/agents/evaluation_agent.py +++ b/backend/app/agents/evaluation_agent.py @@ -61,6 +61,11 @@ def evaluate_project() -> dict: and "setResults(resultsNext)" in frontend_text and "slice(0, 240)" not in frontend_text, "job_progress_ui": "JobProgressBar" in frontend_text and "progressTrack" in frontend_text, + "job_diagnostics_ui": "JobDiagnostics" in frontend_text + and "jobDiagnostics" in frontend_text + and "command?.join" in frontend_text + and "job.cwd" in frontend_text + and "JSON.stringify(job.params" in frontend_text, "gpu_task_selection_ui": "selectedGpuIds" in frontend_text and "gpuSelector" in frontend_text and "jobPayload" in frontend_text diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx index 5ee4dc8..2a3153c 100644 --- a/frontend/src/main.tsx +++ b/frontend/src/main.tsx @@ -41,9 +41,15 @@ type Job = { type: string; status: string; description: string; + command?: string[]; + cwd?: string; + pid?: number | null; + exit_code?: number | null; + error?: string | null; created_at: string; started_at?: string; finished_at?: string; + log_path?: string; log_tail?: string; log_size?: number; params: Record; @@ -1298,6 +1304,7 @@ function App() { {selectedJob && } + {selectedJob && }
{log || "No log selected."}
@@ -1326,6 +1333,37 @@ function App() { ); } +function JobDiagnostics({ job }: { job: Job }) { + const command = job.command?.join(" ") ?? ""; + return ( +
+
+
ID{job.id.slice(0, 12)}
+
PID{job.pid ?? "-"}
+
Exit{job.exit_code ?? "-"}
+
Log{formatBytes(job.log_size)}
+
+ {job.cwd && ( +
+ CWD + {job.cwd} +
+ )} + {!!job.error &&
{job.error}
} + {!!command && ( +
+ Command +
{command}
+
+ )} +
+ Params +
{JSON.stringify(job.params ?? {}, null, 2)}
+
+
+ ); +} + function AgentCheckList({ checks, limit }: { checks: AgentCheck[]; limit: number }) { if (!checks.length) { return

尚未运行验证。

; diff --git a/frontend/src/styles.css b/frontend/src/styles.css index 8f40c26..ea072d5 100644 --- a/frontend/src/styles.css +++ b/frontend/src/styles.css @@ -1346,6 +1346,90 @@ meter { white-space: pre-wrap; } +.jobDiagnostics { + display: grid; + gap: 9px; + margin-top: 12px; +} + +.jobDetailGrid { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: 8px; +} + +.jobDetailGrid div { + min-width: 0; + display: grid; + gap: 3px; + padding: 8px; + border: 1px solid var(--line); + border-radius: 6px; + background: #080a08; +} + +.jobDetailGrid span, +.jobPath span { + color: var(--muted); + font-size: 11px; +} + +.jobDetailGrid strong { + min-width: 0; + color: var(--ink); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.jobPath { + min-width: 0; + display: grid; + gap: 4px; +} + +.jobPath code { + display: block; + padding: 8px; + border: 1px solid var(--line); + border-radius: 6px; + background: #080a08; + color: var(--muted); + overflow-wrap: anywhere; +} + +.jobError { + padding: 8px; + border: 1px solid rgba(240, 113, 103, 0.45); + border-radius: 6px; + color: var(--red); + background: rgba(240, 113, 103, 0.08); + overflow-wrap: anywhere; +} + +.jobDetailBlock { + min-width: 0; + border: 1px solid var(--line); + border-radius: 6px; + background: #080a08; +} + +.jobDetailBlock summary { + cursor: pointer; + padding: 8px; + color: var(--green); + font-size: 12px; +} + +.jobDetailBlock pre { + min-height: 0; + max-height: 180px; + margin: 0; + border-width: 1px 0 0; + border-radius: 0; + overflow-wrap: anywhere; +} + .curvePanel { display: grid; gap: 10px; @@ -1479,6 +1563,7 @@ meter { .gpuPicker, .taskCheckList, .agentCheckList, + .jobDetailGrid, .qualityStats, .qualityChecks { grid-template-columns: repeat(2, minmax(0, 1fr));