diff --git a/studio/frontend/src/features/images/diffusion-train-dialog.tsx b/studio/frontend/src/features/images/diffusion-train-dialog.tsx index 17d6dc8193..016dc3770f 100644 --- a/studio/frontend/src/features/images/diffusion-train-dialog.tsx +++ b/studio/frontend/src/features/images/diffusion-train-dialog.tsx @@ -344,7 +344,7 @@ export function DiffusionTrainDialog({ {uploading ? "Uploading..." : "Upload"} -

+

10-50 images work well. Optional captions: a .txt per image (same filename) or a metadata.jsonl; without them the trigger prompt below captions every image. You can upload more into the same name later. @@ -352,7 +352,7 @@ export function DiffusionTrainDialog({ )} {selectedDataset && selectedDataset.caption_count === 0 && ( -

+

No caption files in this dataset - the trigger prompt below will be used as the caption for every image.

@@ -480,7 +480,7 @@ export function DiffusionTrainDialog({ : status.message} {status.loss != null && !completed && <> · loss {status.loss.toFixed(4)}} {status.lora_path && ( -
Saved: {status.lora_path}
+
Saved: {status.lora_path}
)} diff --git a/studio/frontend/src/features/images/images-page.tsx b/studio/frontend/src/features/images/images-page.tsx index 748296040e..bd8c39ea37 100644 --- a/studio/frontend/src/features/images/images-page.tsx +++ b/studio/frontend/src/features/images/images-page.tsx @@ -512,7 +512,7 @@ function ResolvedBadge({ const resolved = status?.resolved?.[controlKey]; if (!resolved || resolved.source !== "auto") return null; const badge = ( - + Auto: {formatResolvedValue(controlKey, resolved.value)} ); @@ -567,7 +567,7 @@ function AdvancedSelect({ - {desc &&

{desc}

} + {desc &&

{desc}

} ); } @@ -949,7 +949,7 @@ function RecipePopover({

Generation settings

-

{formatTimestamp(image.created_at)}

+

{formatTimestamp(image.created_at)}

diff --git a/studio/frontend/src/features/images/train/dataset-labeling-grid.tsx b/studio/frontend/src/features/images/train/dataset-labeling-grid.tsx index f3d262079f..5c60e4f233 100644 --- a/studio/frontend/src/features/images/train/dataset-labeling-grid.tsx +++ b/studio/frontend/src/features/images/train/dataset-labeling-grid.tsx @@ -125,7 +125,7 @@ function LabelTile({ type="button" onClick={remove} disabled={deleting} - className="absolute right-1 top-1 rounded-md bg-background/80 px-1.5 py-0.5 text-[11px] text-muted-foreground opacity-0 transition-opacity hover:bg-background hover:text-destructive group-hover:opacity-100 focus:opacity-100" + className="absolute right-1 top-1 rounded-md bg-background/80 px-1.5 py-0.5 text-ui-11 text-muted-foreground opacity-0 transition-opacity hover:bg-background hover:text-destructive group-hover:opacity-100 focus:opacity-100" > {deleting ? "..." : "Remove"} @@ -140,10 +140,10 @@ function LabelTile({ rows={2} spellCheck={false} placeholder="Describe this image..." - className="min-h-[3rem] resize-none text-[11px]" + className="min-h-[3rem] resize-none text-ui-11" aria-label={`Caption for ${record.filename}`} /> -
+
{record.filename} @@ -214,7 +214,7 @@ export function DatasetLabelingGrid({ ); if (error) { - return

{error}

; + return

{error}

; } if (records === null) { return ( @@ -224,7 +224,7 @@ export function DatasetLabelingGrid({ ); } if (records.length === 0) { - return

This dataset has no images yet.

; + return

This dataset has no images yet.

; } const uncaptioned = records.filter((r) => !r.caption || r.caption.trim() === "").length; @@ -236,7 +236,7 @@ export function DatasetLabelingGrid({ return (
-
+
{total} image{total === 1 ? "" : "s"} {uncaptioned > 0 ? ` · ${uncaptioned} without a caption` : " · all captioned"} diff --git a/studio/frontend/src/features/images/train/dataset-showcase.tsx b/studio/frontend/src/features/images/train/dataset-showcase.tsx index 317e863dd0..7998c1ddc6 100644 --- a/studio/frontend/src/features/images/train/dataset-showcase.tsx +++ b/studio/frontend/src/features/images/train/dataset-showcase.tsx @@ -112,7 +112,7 @@ export function DatasetShowcase({ className="hover-scrollbar flex w-full items-center gap-1.5 overflow-x-auto rounded-lg border border-border bg-muted/20 p-1.5 text-left transition-colors hover:border-foreground/20" > {names === null ? ( -
+
Loading preview...
) : ( @@ -123,7 +123,7 @@ export function DatasetShowcase({ {remaining > 0 && (
+{remaining} - more + more
)} diff --git a/studio/frontend/src/features/images/train/diffusion-charts.tsx b/studio/frontend/src/features/images/train/diffusion-charts.tsx index 9d18334bac..07029324b9 100644 --- a/studio/frontend/src/features/images/train/diffusion-charts.tsx +++ b/studio/frontend/src/features/images/train/diffusion-charts.tsx @@ -125,7 +125,7 @@ export function DiffusionCharts({ showAvgLine={true} scale="linear" /> -

+

Per-step loss is noisy by design: every step samples a random noise level. Watch the smoothed line for the trend, not the raw jitter.

diff --git a/studio/frontend/src/features/images/train/diffusion-train-panel.tsx b/studio/frontend/src/features/images/train/diffusion-train-panel.tsx index 53b5aecaa0..d2081f7bd7 100644 --- a/studio/frontend/src/features/images/train/diffusion-train-panel.tsx +++ b/studio/frontend/src/features/images/train/diffusion-train-panel.tsx @@ -910,7 +910,7 @@ export function DiffusionTrainPanel({ Linear decay -

+

Constant is fine for most runs.

@@ -933,7 +933,7 @@ export function DiffusionTrainPanel({ Off (faster steps) -

+

Less VRAM, slightly slower steps.

@@ -964,7 +964,7 @@ export function DiffusionTrainPanel({ ))} -

+

{familyUntrainable ? ( // The reason itself (the backend's bf16-preflight text) already shows in // the family picker's vram_note line above. @@ -995,7 +995,7 @@ export function DiffusionTrainPanel({ fp32 (no mixed) -

+

bf16 is right for modern GPUs.

@@ -1018,7 +1018,7 @@ export function DiffusionTrainPanel({ Off -

+

Slower first step, faster after.

@@ -1036,7 +1036,7 @@ export function DiffusionTrainPanel({

Train a LoRA

-

+

Teach a model a style or subject from your own images.

@@ -1057,7 +1057,7 @@ export function DiffusionTrainPanel({ {family?.vram_note && ( -

{family.vram_note}

+

{family.vram_note}

)}
@@ -1127,7 +1127,7 @@ export function DiffusionTrainPanel({ {importingId && ( -

+

Importing {examples.find((e) => e.id === importingId)?.label ?? "example"}...

)} @@ -1170,7 +1170,7 @@ export function DiffusionTrainPanel({ {/* Count and Upload appear only once files are picked. */} {pickedFileCount > 0 && ( <> - + {pickedFileCount} file{pickedFileCount === 1 ? "" : "s"} selected
-

+

10-50 images is plenty. Captions are optional.

@@ -1214,7 +1214,7 @@ export function DiffusionTrainPanel({ /> )} {selectedDataset.caption_count === 0 && !gridOpen && ( -

+

No captions yet, so the trigger prompt describes every image.

)} @@ -1232,7 +1232,7 @@ export function DiffusionTrainPanel({ {/* Trigger + adapter name (trigger first: it describes the dataset, the name just labels the output) */} {fullyCaptioned ? ( -

+

All {selectedDataset?.image_count} images have captions, so no trigger prompt is needed.

@@ -1245,7 +1245,7 @@ export function DiffusionTrainPanel({ onChange={(e) => setInstancePrompt(e.target.value)} className="h-8 text-xs" /> -

+

The words you will use later to get this style back.

@@ -1259,7 +1259,7 @@ export function DiffusionTrainPanel({ onChange={(e) => setOutputDir(e.target.value)} className="h-8 text-xs" /> -

+

Its name in the Create tab's picker.

@@ -1323,7 +1323,7 @@ export function DiffusionTrainPanel({ } /> -

+

{viewRun.family ? `${viewRun.family} - ` : ""} {viewRun.base_model || ""} {viewRun.ended_at @@ -1367,7 +1367,7 @@ export function DiffusionTrainPanel({ {trainingSettings} -

+

Progress and charts take over here once training starts.

@@ -1394,14 +1394,14 @@ export function DiffusionTrainPanel({
{r.saved && ( - + adapter saved )} - + {r.status} - + {r.ended_at ? new Date(r.ended_at * 1000).toLocaleString() : ""} @@ -1457,7 +1457,7 @@ export function DiffusionTrainPanel({ /> {status?.message && ( -

{status.message}

+

{status.message}

)} {running && ( Clear all videos