Spaces:
Running
Running
| // Recommended settings presets. Each preset can set the text engine/model, voice | |
| // provider, and portrait model together. Manual changes move the picker to Custom. | |
| import { setEngine, getEngineId, setModel, currentModelId, listModels, onModelChange } from '/web/runtime.js' | |
| import { setTtsEngine, getTtsEngineId, onTtsEngineChange } from '/web/tts.js' | |
| import { setImageEngine, getImageEngineId, onImageEngineChange } from '/web/imagen.js' | |
| import { setCodingModel, getCodingModelId, onCodingModelChange } from '/web/codingModel.js' | |
| export const PRESETS = [ | |
| { id: 'build-small', label: 'BUILD SMALL', engine: 'server', model: 'tiny-aya-global-zerogpu', family: 'tiny-aya', voice: 'voxcpm', image: 'klein-zerogpu', coding: 'mellum2-zerogpu', sub: 'Tiny Aya - VoxCPM2 - FLUX.2 klein - Mellum2 (Nemotron NIM fallback)' }, | |
| { id: 'high', label: 'High', engine: 'webllm', model: 'qwen3-0.6b', family: 'qwen3', voice: 'kokoro', image: '', coding: 'mellum2-zerogpu', sub: 'Qwen3 - Kokoro 82M' }, | |
| { id: 'medium', label: 'Medium', engine: 'transformers', model: 'qwen2.5-0.5b', family: 'qwen2.5', voice: 'kitten', image: '', coding: 'mellum2-zerogpu', sub: 'Qwen2.5 - Kitten TTS' }, | |
| { id: 'low', label: 'Low', engine: 'transformers', model: 'qwen2.5-0.5b', family: 'qwen2.5', voice: 'webspeech', image: '', coding: 'mellum2-zerogpu', sub: 'Qwen2.5 - Web Speech' }, | |
| ] | |
| const KEY = 'tinyarmy.qualityPreset' | |
| const VALID = new Set([...PRESETS.map((p) => p.id), 'custom']) | |
| const byId = (id) => PRESETS.find((p) => p.id === id) | |
| function resolveModel(p) { | |
| const ms = listModels() | |
| const m = ms.find((x) => x.id === p.model) || ms.find((x) => x.id.startsWith(p.family)) | |
| return m ? m.id : '' | |
| } | |
| export function detectPreset() { | |
| const eid = getEngineId() | |
| const mid = currentModelId() | |
| const voice = getTtsEngineId() | |
| const image = getImageEngineId() | |
| const coding = getCodingModelId() | |
| const p = PRESETS.find((x) => | |
| (!x.engine || eid === x.engine) && | |
| (mid === x.model || mid.startsWith(x.family)) && | |
| voice === x.voice && | |
| (!x.image || image === x.image) && | |
| (!x.coding || coding === x.coding)) | |
| return p ? p.id : 'custom' | |
| } | |
| let _applying = false | |
| let _current = (() => { | |
| let saved = '' | |
| try { saved = localStorage.getItem(KEY) || '' } catch { /* ignore */ } | |
| if (!VALID.has(saved)) return detectPreset() | |
| if (saved === 'custom') return 'custom' | |
| return detectPreset() === saved ? saved : detectPreset() | |
| })() | |
| export const getActivePreset = () => _current | |
| function commit(id) { | |
| _current = id | |
| try { localStorage.setItem(KEY, id) } catch { /* ignore */ } | |
| for (const fn of _listeners) { try { fn(id) } catch { /* ignore */ } } | |
| } | |
| export function applyPreset(id) { | |
| const p = byId(id) | |
| if (!p) return | |
| _applying = true | |
| if (p.engine) setEngine(p.engine) | |
| const mid = resolveModel(p) | |
| if (mid) setModel(mid) | |
| setTtsEngine(p.voice) | |
| if (p.image) setImageEngine(p.image) | |
| if (p.coding) setCodingModel(p.coding) | |
| _applying = false | |
| commit(id) | |
| } | |
| const _listeners = new Set() | |
| export function onPresetChange(fn) { _listeners.add(fn); return () => _listeners.delete(fn) } | |
| const _onManual = () => { if (!_applying) commit('custom') } | |
| onModelChange(_onManual) | |
| onTtsEngineChange(_onManual) | |
| onImageEngineChange(_onManual) | |
| onCodingModelChange(_onManual) | |