mirror of
https://github.com/mudler/LocalAI.git
synced 2026-10-28 17:18:49 -04:00
Studio and Talk were compiled into the web bundle and always listed in the Add-ons drawer. They are add-ons now, like Voice, Face, fine-tuning and quantization: a person installs and removes them, the drawer lists them only while they are installed, and they are packaged the same way. Move the pages, their components, hooks and helpers into addons/studio and addons/talk. Each has a manifest, a UI bundle, a release platform matrix and a catalog template, and is built by the compat mode of the shared builder. The core API stays where it is: the pages call it with the signed-in person's session. The history keeps its browser storage keys. The unit tests of the moved helpers move with them. In the core, drop the two pages, the Create group of the sidebar (Chat joins Home and Models in the old layout), the built-in catalog entries (the catalog is empty) and the talk locale namespace. The old addresses (/app/studio, /app/talk and the generator links) redirect to the add-on pages, with the model as ?model=. The Home /studio command is offered only while the Studio add-on is installed and opens it. The release workflow and its tests now list seven add-ons. Assisted-by: Claude Code:claude-sonnet-5-5 go node Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
68 lines
2.6 KiB
JavaScript
68 lines
2.6 KiB
JavaScript
import { useCallback, useEffect, useMemo, useState } from 'react'
|
|
import { clearAllMediaHistory, FAVOURITES_KEY, readAllMediaHistory, useMediaHistory } from './useMediaHistory'
|
|
import { use3DHistory } from './use3DHistory'
|
|
import { collectWork, pruneIds, toggleId } from '../utils/studioWork'
|
|
|
|
function readFavourites() {
|
|
try {
|
|
const stored = JSON.parse(localStorage.getItem(FAVOURITES_KEY) || '[]')
|
|
return Array.isArray(stored) ? stored.filter(id => typeof id === 'string') : []
|
|
} catch {
|
|
return []
|
|
}
|
|
}
|
|
|
|
function writeFavourites(ids) {
|
|
try {
|
|
if (ids.length === 0) localStorage.removeItem(FAVOURITES_KEY)
|
|
else localStorage.setItem(FAVOURITES_KEY, JSON.stringify(ids))
|
|
} catch { /* quota or private mode: the star simply does not stick */ }
|
|
}
|
|
|
|
// Everything the Studio front page shows as "your work": the entries each
|
|
// workspace stored, in one list, with favourites. The browser-storage lists are
|
|
// read once on mount, except images: inline upscaling writes through the same
|
|
// image history hook and merges its live entries. 3D arrives from IndexedDB.
|
|
//
|
|
// `ready` is false until 3D has answered, so the page can show a skeleton
|
|
// instead of flashing an empty state for work that is a moment away.
|
|
export function useStudioWork() {
|
|
const { addEntry: addImageEntry, historyProps: imageHistory } = useMediaHistory('image')
|
|
const clearImages = imageHistory.onClearAll
|
|
const [media, setMedia] = useState(() => readAllMediaHistory())
|
|
const [favourites, setFavourites] = useState(readFavourites)
|
|
const { entries: threeD, clearAll: clearThreeD } = use3DHistory()
|
|
const [ready, setReady] = useState(false)
|
|
|
|
// use3DHistory starts with [] and fills from IndexedDB; one tick later it has
|
|
// answered either way, which is all "ready" needs to mean.
|
|
useEffect(() => {
|
|
const id = setTimeout(() => setReady(true), 0)
|
|
return () => clearTimeout(id)
|
|
}, [])
|
|
useEffect(() => { if (threeD.length > 0) setReady(true) }, [threeD])
|
|
|
|
const items = useMemo(
|
|
() => collectWork({ ...media, image: imageHistory.entries }, threeD, { favourites }),
|
|
[media, imageHistory.entries, threeD, favourites],
|
|
)
|
|
|
|
const toggleFavourite = useCallback((id) => {
|
|
setFavourites(prev => {
|
|
const next = toggleId(pruneIds(prev, items), id)
|
|
writeFavourites(next)
|
|
return next
|
|
})
|
|
}, [items])
|
|
|
|
const clearHistory = useCallback(async () => {
|
|
clearImages()
|
|
clearAllMediaHistory()
|
|
setMedia(readAllMediaHistory())
|
|
setFavourites([])
|
|
await clearThreeD()
|
|
}, [clearThreeD, clearImages])
|
|
|
|
return { items, ready, addImageEntry, toggleFavourite, clearHistory }
|
|
}
|