Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 2 additions & 18 deletions client/src/components/media/MediaLightbox.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -378,26 +378,10 @@ function SettingsPane({
// optional prompt) so a watermark-defeat pass can be tuned without leaving the
// lightbox. Slider bounds come from the server (`regenBounds`) so the floor
// stays in lock-step with route validation.
const regenMin = typeof regenBounds?.strengthMin === 'number' ? regenBounds.strengthMin : 0.02;
const regenMax = typeof regenBounds?.strengthMax === 'number' ? regenBounds.strengthMax : 0.6;
const regenDefault = typeof regenBounds?.strengthDefault === 'number' ? regenBounds.strengthDefault : 0.25;
const { strengthMin: regenMin = 0.02, strengthMax: regenMax = 0.6, strengthDefault: regenDefault = 0.25 } = regenBounds || {};
const [regenOpen, setRegenOpen] = useState(false);
const [regenStrength, setRegenStrength] = useState(regenDefault);
const [regenPrompt, setRegenPrompt] = useState('');
const runRegen = async () => {
if (regenerating) return;
setRegenerating(true);
let ok = false;
try {
await onRegenerate(item, { strength: regenStrength, prompt: regenPrompt.trim() || undefined });
ok = true;
} catch {
// Caller toasts its own error; stay open so the user can retry.
} finally {
setRegenerating(false);
}
if (ok) onClose();
};
const starred = !!annotation?.starred;
const closeThenRun = (handler) => {
onClose?.();
Expand Down Expand Up @@ -697,7 +681,7 @@ function SettingsPane({
<button
type="button"
disabled={regenerating}
onClick={runRegen}
onClick={runBusyAction(regenerating, setRegenerating, (it) => onRegenerate(it, { strength: regenStrength, prompt: regenPrompt.trim() || undefined }))}
className="w-full flex items-center justify-center gap-1.5 px-2 py-1.5 text-xs bg-port-accent text-white hover:opacity-90 rounded disabled:opacity-50 disabled:cursor-not-allowed"
>
<Wand2 className="w-3.5 h-3.5" /> {regenerating ? 'Queuing…' : `Regenerate at ${regenStrength.toFixed(2)}`}
Expand Down
11 changes: 6 additions & 5 deletions server/services/imageGen/local.js
Original file line number Diff line number Diff line change
Expand Up @@ -707,13 +707,14 @@ export async function generateImage({ pythonPath, prompt, negativePrompt = '', m
// the watermark-free copy matches the original's resolution. `meta.width/
// height` currently hold the render dims; record those as render* and
// promote the delivered dims so the gallery shows the real file size.
if (upscaleTo && Number(upscaleTo.width) > 0 && Number(upscaleTo.height) > 0
&& (Math.round(upscaleTo.width) !== meta.width || Math.round(upscaleTo.height) !== meta.height)) {
const targetW = Math.round(upscaleTo.width);
const targetH = Math.round(upscaleTo.height);
const targetW = Math.round(Number(upscaleTo?.width));
const targetH = Math.round(Number(upscaleTo?.height));
if (targetW > 0 && targetH > 0 && (targetW !== meta.width || targetH !== meta.height)) {
const resized = await sharp(outputPath)
.resize(targetW, targetH, { fit: 'fill', kernel: 'lanczos3' })
.png({ compressionLevel: 9 })
// compressionLevel 6 (sharp default) — near-identical size to 9 but
// markedly faster, and this re-encode is on the render-completion path.
.png({ compressionLevel: 6 })
.toBuffer()
.catch((err) => { console.warn(`⚠️ Regen upscale failed for ${filename}: ${err?.message || err}`); return null; });
if (resized) {
Expand Down
6 changes: 3 additions & 3 deletions server/services/imageGen/regen.js
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ export async function readImageDimensions(absPath) {
export function buildRegenParams({ filename, sourceAbsPath, sourceMeta = {}, sourceDims = null, model, pythonPath, strength, steps, promptOverride }) {
const src = sourceDims
|| (sourceMeta.width && sourceMeta.height ? { width: Math.round(sourceMeta.width), height: Math.round(sourceMeta.height) } : null);
const hasPrompt = typeof promptOverride === 'string' && promptOverride.trim();
const trimmedPrompt = typeof promptOverride === 'string' ? promptOverride.trim() : '';
// Anchor the variant-grouping lineage at the ROOT original, not the clicked
// image. computeImageVariantGroup groups siblings under a single original
// (an item with no `cleanedFrom`); regenerating a cleaned/regenerated variant
Expand All @@ -226,8 +226,8 @@ export function buildRegenParams({ filename, sourceAbsPath, sourceMeta = {}, sou
mode: IMAGE_GEN_MODE.LOCAL,
pythonPath,
modelId: model.id,
prompt: hasPrompt ? promptOverride : '',
negativePrompt: hasPrompt && typeof sourceMeta.negativePrompt === 'string' ? sourceMeta.negativePrompt : '',
prompt: trimmedPrompt,
negativePrompt: trimmedPrompt && typeof sourceMeta.negativePrompt === 'string' ? sourceMeta.negativePrompt : '',
initImagePath: sourceAbsPath,
initImageStrength: strength,
regenOf: groupRoot,
Expand Down
Loading