feat(heal): add Hybrid Option 2 with Fast Engine and AI Server toggle
This commit is contained in:
@@ -29,9 +29,9 @@ import { offerInstall } from './pwa/install';
|
||||
import { cameraSupported } from './engine/camera';
|
||||
import { clearSession, forgetPhoto, loadPhoto, loadState, savePhoto, saveState, type StudioState } from './engine/session';
|
||||
import { analyzeCustomFrame, clearCustomFrame, loadCustomFrame, saveCustomFrame, type CustomFrameData } from './engine/customFrame';
|
||||
import { keep } from './remember';
|
||||
import { keep, recall } from './remember';
|
||||
import { preloadSuperRes, upscaleJpeg } from './engine/superRes';
|
||||
import { preloadInpaint, clearInpaintCache } from './engine/inpaint';
|
||||
import { preloadInpaint, clearInpaintCache, setAiInpaintMode } from './engine/inpaint';
|
||||
import { api, type Photo, type SavedRecipe } from './api';
|
||||
import { refreshAuth, useAuth } from './auth';
|
||||
import { TIERS } from './config/tiers';
|
||||
@@ -519,6 +519,11 @@ export function Workspace() {
|
||||
const [brushTool, setBrushTool] = useState<'heal' | 'mosaic' | null>(null);
|
||||
const [healR, setHealR] = useState(HEAL_DEFAULT_R);
|
||||
const [mosaicR, setMosaicR] = useState(MOSAIC_DEFAULT_R);
|
||||
const [aiInpaint, setAiInpaint] = useState<boolean>(() => recall('recipescam.heal.ai') === 'true');
|
||||
useEffect(() => {
|
||||
setAiInpaintMode(aiInpaint);
|
||||
keep('recipescam.heal.ai', String(aiInpaint));
|
||||
}, [aiInpaint]);
|
||||
// FX's gradient masks: which shape the next drag on the photo lays down (null
|
||||
// for neither), the masks the recipe holds, and which of them is chosen — the
|
||||
// one whose shape is on the photo and whose knobs are in the panel beside it.
|
||||
@@ -1163,7 +1168,7 @@ export function Workspace() {
|
||||
}, PREVIEW_DEBOUNCE_MS);
|
||||
return () => clearTimeout(timer);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [engine, previewBytes, recipe, preview, frameId, cropEditing, cropLive, cropRect, rotation, straighten, flipH, flipV, useGeotag, gpsInfo, gpsStyle, markOn, markText, markStyle, comparing, shooting]);
|
||||
}, [engine, previewBytes, recipe, preview, frameId, cropEditing, cropLive, cropRect, rotation, straighten, flipH, flipV, useGeotag, gpsInfo, gpsStyle, markOn, markText, markStyle, comparing, shooting, aiInpaint]);
|
||||
|
||||
// The source copy behind previewBytes, re-made only when previewMax moves:
|
||||
// applying a crop upgrades it, CANCEL/UNDO brings the 1600px one back.
|
||||
@@ -2785,7 +2790,7 @@ export function Workspace() {
|
||||
if (!brushTool) return;
|
||||
const dismiss = (e: PointerEvent) => {
|
||||
const el = e.target as HTMLElement | null;
|
||||
if (!el?.closest('.rail, .chip') || el.closest('.chip[data-key="heal"], .chip[data-key="mosaic"]')) return;
|
||||
if (!el?.closest('.rail, .chip') || el.closest('.chip[data-key^="heal"], .chip[data-key^="mosaic"]')) return;
|
||||
setBrushTool(null);
|
||||
};
|
||||
window.addEventListener('pointerdown', dismiss, true);
|
||||
@@ -3719,6 +3724,16 @@ export function Workspace() {
|
||||
}
|
||||
},
|
||||
},
|
||||
...(brushTool === 'heal'
|
||||
? [
|
||||
{
|
||||
key: 'heal-ai',
|
||||
label: aiInpaint ? '✨ AI SERVER' : '⚡ FAST ENGINE',
|
||||
active: aiInpaint,
|
||||
onClick: () => setAiInpaint((v: boolean) => !v),
|
||||
},
|
||||
]
|
||||
: []),
|
||||
...(healSpots.length ? [{ key: 'heal-clear', label: 'CLEAR', onClick: clearHealSpots }] : []),
|
||||
{
|
||||
key: 'mosaic',
|
||||
|
||||
Reference in New Issue
Block a user