diff --git a/.changelog/NEXT.md b/.changelog/NEXT.md index 37cf37b1d4..2cd2be7a9d 100644 --- a/.changelog/NEXT.md +++ b/.changelog/NEXT.md @@ -14,6 +14,7 @@ TBD - **Brain → Links: edit a link's URL**: the per-link edit form now exposes the URL alongside the title (each with a visible label so they're unambiguous even when the title defaults to the URL). Changing the URL re-derives the GitHub repo metadata, guards against duplicate URLs (409), and resets stale clone state so a cloned repo's local path can't point at the wrong target. - **Base style image (style probe)** on a universe: generate a canonical image from the universe's embrace/avoid influences as the positive/negative prompt, with no character or subject — to preview the world's base visual emphasis. `styleNotes` is intentionally NOT mixed into the probe prompt because it never reaches the image model on any downstream prompt (canon refs, variations, sheets, comic pages) — including it would misrepresent what those renders will look like. Triggerable from both the Universe Builder (under the style/influences editor) and the Story Builder's Universe Aesthetic step; the result persists on the universe (`styleImageRefs`) so both surfaces share it. Includes a "Regenerate" affordance to re-roll the probe once an image already exists (new filenames append to `styleImageRefs[]` so prior renders survive as walk-back fallbacks). - **Reader Map** on a series arc (`series.arc.readerMap`): a distinct audience-experience roadmap — hooks, payoffs, emotional beats, and cliffhangers across the arc — built on top of the Vonnegut story shape, separate from the protagonist arc. Generated and refined via the new Story Builder reader-map step (also preserved by arc regeneration). +- **Image + Video Gen: inline model download status**. The model picker on both pages now shows whether the selected model's weights are already in the local HuggingFace cache. Available models get a green "Available · 7.8 GB" badge; missing ones get a "Download (~est)" button that pre-fetches the repo over SSE with a live progress bar (so users learn about a multi-GB pull before hitting Render instead of being surprised by a silent lazy download mid-generation). Hitting Render without pre-downloading still works — the existing lazy-download path is the fallback. The video form also surfaces the active text encoder (a separate ~7–25 GB Gemma pull) with its own button. New endpoints: `GET /api/image-gen/models/status`, `GET /api/image-gen/models/:id/download` (SSE), `GET /api/video-gen/models/status`, `GET /api/video-gen/models/:id/download` (SSE), `GET /api/video-gen/text-encoder/download` (SSE). Cache detection lives in `server/lib/hfCache.js` (`inspectModelCache`); download orchestration in `server/lib/hfDownload.js` and the new `scripts/hf_download_repo.py` helper (runs in the FLUX.2 venv, falls back to the mflux pythonPath). Mflux legacy `dev` / `schnell` map to their canonical `black-forest-labs/FLUX.1-*` repos so they get the same badge as every other entry. - Local LLMs: when an Ollama model pull fails with `412: requires a newer version of Ollama`, PortOS now auto-upgrades Ollama in place and retries the install — no confirm click. On macOS with `/Applications/Ollama.app` present, this downloads the latest `Ollama-darwin.zip` directly from GitHub releases, force-kills the running Ollama, replaces the `.app` bundle, strips quarantine, relaunches, and polls `/api/version` until the new binary is serving. (The old brew-only path silently left the old binary running, because `/usr/local/bin/ollama` symlinks into the `.app` bundle — even a successful `brew upgrade` doesn't change which binary is on disk inside the `.app`.) On Linux it still re-runs the official Ollama install script; for headless macOS installs (brew formula only, no `.app`), it still runs `brew upgrade ollama`. The UI now shows a prominent yellow warning banner with live step-by-step progress for the whole upgrade flow, instead of a quiet inline confirm row. Failed `brew` runs now also surface the actual stderr (e.g. `Error: ollama not installed`) instead of just an exit code. ## Changed diff --git a/client/src/components/imageGen/ImageGenControls.jsx b/client/src/components/imageGen/ImageGenControls.jsx index 086fe79b42..b301fc6e45 100644 --- a/client/src/components/imageGen/ImageGenControls.jsx +++ b/client/src/components/imageGen/ImageGenControls.jsx @@ -13,6 +13,7 @@ import { filterResolutions, resolveResolutionLabel } from '../../lib/imageGenRes import { randomSeed } from '../../lib/genUtils'; import { RUNNER_FAMILIES } from '../../lib/runnerFamilies'; import { IMAGE_GEN_MODE } from '../../lib/imageGenBackends'; +import ModelDownloadBadge, { deriveSizeEstimate } from '../media/ModelDownloadBadge'; const QUANTIZE_OPTIONS = [ { value: '3', label: '3-bit' }, @@ -39,6 +40,14 @@ export default function ImageGenControls({ // Optional column override — defaults to 2/3 like the Image Gen page. // Pass e.g. "grid-cols-2 sm:grid-cols-4" to fit a denser layout. className = 'grid grid-cols-2 sm:grid-cols-3 gap-3', + // Pre-download badge integration. `modelStatus` is the per-model entry from + // useModelDownloadStatus().getStatus(modelId); `onModelDownload` / + // `onModelDownloadCancel` are optional triggers. Omitting the props hides + // the badge — callers that don't care (Universe Builder batch render) opt + // out by simply not passing them. + modelStatus = null, + onModelDownload, + onModelDownloadCancel, }) { const isLocal = mode === IMAGE_GEN_MODE.LOCAL; const isCodex = mode === IMAGE_GEN_MODE.CODEX; @@ -71,6 +80,14 @@ export default function ImageGenControls({ > {models.map((m) => )} + {onModelDownload && modelStatus && ( + onModelDownload(modelId)} + onCancel={onModelDownloadCancel} + estimateLabel={deriveSizeEstimate(currentModel?.name)} + /> + )} )} diff --git a/client/src/components/media/ModelDownloadBadge.jsx b/client/src/components/media/ModelDownloadBadge.jsx new file mode 100644 index 0000000000..3898c598ef --- /dev/null +++ b/client/src/components/media/ModelDownloadBadge.jsx @@ -0,0 +1,107 @@ +// Inline "Available · 7.8 GB" / "Download (~8 GB)" badge for the image and +// video gen model pickers. Drops below the model