polats commited on
Commit
de78f87
·
1 Parent(s): b9bfeb6

Add Build Small recommended preset

Browse files
Files changed (5) hide show
  1. web/imagen.js +2 -2
  2. web/qualityBar.js +2 -2
  3. web/qualityPreset.js +24 -21
  4. web/runtime.js +1 -1
  5. web/tts.js +2 -2
web/imagen.js CHANGED
@@ -1,7 +1,7 @@
1
  // Image facade — mirrors tts.js. Picks the active portrait engine (local Z-Image on your
2
  // GPU, or cloud FLUX; in-browser SD-Turbo / Janus get added here later) and exposes one
3
  // generatePortrait(). The persona panel + the Settings image bar import only from here.
4
- import { engineLocal as zimagelocal, engineKleinZeroGpu as klein, engineCloud as flux, engineCloudDev as fluxdev, isLocalhost } from '/web/imagenServer.js'
5
  import { engine as bonsai } from '/web/imagenBonsai.js'
6
 
7
  const ENGINES = [zimagelocal, klein, bonsai, flux, fluxdev]
@@ -12,7 +12,7 @@ let activeId = (() => {
12
  let saved = ''
13
  try { saved = localStorage.getItem(KEY) || '' } catch { /* ignore */ }
14
  const e = ENGINES.find((x) => x.id === saved)
15
- return e && e.available() ? saved : (isLocalhost() ? 'zimage-local' : 'klein-zerogpu')
16
  })()
17
 
18
  const eng = () => ENGINES.find((e) => e.id === activeId) || ENGINES.find((e) => e.available()) || ENGINES[0]
 
1
  // Image facade — mirrors tts.js. Picks the active portrait engine (local Z-Image on your
2
  // GPU, or cloud FLUX; in-browser SD-Turbo / Janus get added here later) and exposes one
3
  // generatePortrait(). The persona panel + the Settings image bar import only from here.
4
+ import { engineLocal as zimagelocal, engineKleinZeroGpu as klein, engineCloud as flux, engineCloudDev as fluxdev } from '/web/imagenServer.js'
5
  import { engine as bonsai } from '/web/imagenBonsai.js'
6
 
7
  const ENGINES = [zimagelocal, klein, bonsai, flux, fluxdev]
 
12
  let saved = ''
13
  try { saved = localStorage.getItem(KEY) || '' } catch { /* ignore */ }
14
  const e = ENGINES.find((x) => x.id === saved)
15
+ return e && e.available() ? saved : 'klein-zerogpu'
16
  })()
17
 
18
  const eng = () => ENGINES.find((e) => e.id === activeId) || ENGINES.find((e) => e.available()) || ENGINES[0]
web/qualityBar.js CHANGED
@@ -1,7 +1,7 @@
1
  // "Recommended settings" — a High/Medium/Low/Custom preset picker (sets the LLM model +
2
  // voice provider together) plus an expandable "Your device" readout for debugging and
3
  // benchmarking. Mounted at the TOP of the Settings page, above Local AI Model.
4
- import { PRESETS, applyPreset, getActivePreset, onPresetChange } from '/web/qualityPreset.js'
5
  import { gatherDeviceInfo, recommendPreset } from '/web/deviceInfo.js'
6
 
7
  const presetLabel = (id) => (PRESETS.find((p) => p.id === id) || {}).label || id
@@ -19,7 +19,7 @@ function el(tag, props = {}, kids = []) {
19
 
20
  export function mountQualityBar(host) {
21
  // Preset buttons (+ a derived "Custom" that only highlights, never applies).
22
- const OPTS = [...PRESETS, { id: 'custom', label: 'Custom', sub: 'Your own model + voice' }]
23
  const btns = {}
24
  const row = el('div', { class: 'tac-preset-row' }, OPTS.map((p) => {
25
  const b = el('button', { class: 'tac-preset-btn', type: 'button', 'data-id': p.id },
 
1
  // "Recommended settings" — a High/Medium/Low/Custom preset picker (sets the LLM model +
2
  // voice provider together) plus an expandable "Your device" readout for debugging and
3
  // benchmarking. Mounted at the TOP of the Settings page, above Local AI Model.
4
+ import { PRESETS, applyPreset, getActivePreset, onPresetChange, detectPreset } from '/web/qualityPreset.js'
5
  import { gatherDeviceInfo, recommendPreset } from '/web/deviceInfo.js'
6
 
7
  const presetLabel = (id) => (PRESETS.find((p) => p.id === id) || {}).label || id
 
19
 
20
  export function mountQualityBar(host) {
21
  // Preset buttons (+ a derived "Custom" that only highlights, never applies).
22
+ const OPTS = [...PRESETS, { id: 'custom', label: 'Custom', sub: 'Your own model + voice + portrait' }]
23
  const btns = {}
24
  const row = el('div', { class: 'tac-preset-row' }, OPTS.map((p) => {
25
  const b = el('button', { class: 'tac-preset-btn', type: 'button', 'data-id': p.id },
web/qualityPreset.js CHANGED
@@ -1,40 +1,40 @@
1
- // Quality presets a game-graphics-style High/Medium/Low/Custom picker that sets BOTH
2
- // the in-browser LLM model and the voice provider at once. Picking a preset applies it;
3
- // changing the model or voice by hand drops the picker to "Custom" (even if the new combo
4
- // happens to equal another preset — like a game's graphics dropdown). The choice is
5
- // persisted (and the model/voice themselves are persisted by runtime.js / tts.js), so it
6
- // survives a refresh.
7
- import { setModel, currentModelId, listModels, onModelChange } from '/web/runtime.js'
8
  import { setTtsEngine, getTtsEngineId, onTtsEngineChange } from '/web/tts.js'
 
9
 
10
- // model = preferred exact id; family = prefix fallback if the active engine lacks it
11
- // (e.g. Transformers.js has no Qwen3 — then High can't be honored and reads as Custom).
12
  export const PRESETS = [
13
- { id: 'high', label: 'High', model: 'qwen3-0.6b', family: 'qwen3', voice: 'kokoro', sub: 'Qwen3 · Kokoro 82M' },
14
- { id: 'medium', label: 'Medium', model: 'qwen2.5-0.5b', family: 'qwen2.5', voice: 'kitten', sub: 'Qwen2.5 · Kitten TTS' },
15
- { id: 'low', label: 'Low', model: 'qwen2.5-0.5b', family: 'qwen2.5', voice: 'webspeech', sub: 'Qwen2.5 · Web Speech' },
 
16
  ]
17
  const KEY = 'tinyarmy.qualityPreset'
18
  const VALID = new Set([...PRESETS.map((p) => p.id), 'custom'])
19
 
20
  const byId = (id) => PRESETS.find((p) => p.id === id)
21
- // Resolve a preset's model to an id that exists in the ACTIVE engine's catalog.
22
  function resolveModel(p) {
23
  const ms = listModels()
24
  const m = ms.find((x) => x.id === p.model) || ms.find((x) => x.id.startsWith(p.family))
25
  return m ? m.id : ''
26
  }
27
 
28
- // Which preset does the current (model, voice) match? 'custom' if none.
29
  export function detectPreset() {
30
- const mid = currentModelId(), v = getTtsEngineId()
31
- const p = PRESETS.find((x) => (mid === x.model || mid.startsWith(x.family)) && v === x.voice)
 
 
 
 
 
 
 
32
  return p ? p.id : 'custom'
33
  }
34
 
35
  let _applying = false
36
- // The active preset id. Load the saved one, but only trust a saved preset id if the
37
- // persisted model+voice still match it; honor a saved 'custom' as-is.
38
  let _current = (() => {
39
  let saved = ''
40
  try { saved = localStorage.getItem(KEY) || '' } catch { /* ignore */ }
@@ -55,16 +55,19 @@ export function applyPreset(id) {
55
  const p = byId(id)
56
  if (!p) return
57
  _applying = true
 
58
  const mid = resolveModel(p)
59
- if (mid) setModel(mid) // fires onModelChange (ignored while _applying)
60
- setTtsEngine(p.voice) // fires onTtsEngineChange (ignored while _applying)
 
61
  _applying = false
62
  commit(id)
63
  }
64
 
65
  const _listeners = new Set()
66
  export function onPresetChange(fn) { _listeners.add(fn); return () => _listeners.delete(fn) }
67
- // A model/voice change NOT caused by applyPreset = a manual edit → Custom.
68
  const _onManual = () => { if (!_applying) commit('custom') }
69
  onModelChange(_onManual)
70
  onTtsEngineChange(_onManual)
 
 
1
+ // Recommended settings presets. Each preset can set the text engine/model, voice
2
+ // provider, and portrait model together. Manual changes move the picker to Custom.
3
+ import { setEngine, getEngineId, setModel, currentModelId, listModels, onModelChange } from '/web/runtime.js'
 
 
 
 
4
  import { setTtsEngine, getTtsEngineId, onTtsEngineChange } from '/web/tts.js'
5
+ import { setImageEngine, getImageEngineId, onImageEngineChange } from '/web/imagen.js'
6
 
 
 
7
  export const PRESETS = [
8
+ { id: 'build-small', label: 'BUILD SMALL', engine: 'server', model: 'tiny-aya-global-zerogpu', family: 'tiny-aya', voice: 'voxcpm', image: 'klein-zerogpu', sub: 'Tiny Aya - VoxCPM2 - FLUX.2 klein' },
9
+ { id: 'high', label: 'High', engine: 'webllm', model: 'qwen3-0.6b', family: 'qwen3', voice: 'kokoro', image: '', sub: 'Qwen3 - Kokoro 82M' },
10
+ { id: 'medium', label: 'Medium', engine: 'transformers', model: 'qwen2.5-0.5b', family: 'qwen2.5', voice: 'kitten', image: '', sub: 'Qwen2.5 - Kitten TTS' },
11
+ { id: 'low', label: 'Low', engine: 'transformers', model: 'qwen2.5-0.5b', family: 'qwen2.5', voice: 'webspeech', image: '', sub: 'Qwen2.5 - Web Speech' },
12
  ]
13
  const KEY = 'tinyarmy.qualityPreset'
14
  const VALID = new Set([...PRESETS.map((p) => p.id), 'custom'])
15
 
16
  const byId = (id) => PRESETS.find((p) => p.id === id)
17
+
18
  function resolveModel(p) {
19
  const ms = listModels()
20
  const m = ms.find((x) => x.id === p.model) || ms.find((x) => x.id.startsWith(p.family))
21
  return m ? m.id : ''
22
  }
23
 
 
24
  export function detectPreset() {
25
+ const eid = getEngineId()
26
+ const mid = currentModelId()
27
+ const voice = getTtsEngineId()
28
+ const image = getImageEngineId()
29
+ const p = PRESETS.find((x) =>
30
+ (!x.engine || eid === x.engine) &&
31
+ (mid === x.model || mid.startsWith(x.family)) &&
32
+ voice === x.voice &&
33
+ (!x.image || image === x.image))
34
  return p ? p.id : 'custom'
35
  }
36
 
37
  let _applying = false
 
 
38
  let _current = (() => {
39
  let saved = ''
40
  try { saved = localStorage.getItem(KEY) || '' } catch { /* ignore */ }
 
55
  const p = byId(id)
56
  if (!p) return
57
  _applying = true
58
+ if (p.engine) setEngine(p.engine)
59
  const mid = resolveModel(p)
60
+ if (mid) setModel(mid)
61
+ setTtsEngine(p.voice)
62
+ if (p.image) setImageEngine(p.image)
63
  _applying = false
64
  commit(id)
65
  }
66
 
67
  const _listeners = new Set()
68
  export function onPresetChange(fn) { _listeners.add(fn); return () => _listeners.delete(fn) }
69
+
70
  const _onManual = () => { if (!_applying) commit('custom') }
71
  onModelChange(_onManual)
72
  onTtsEngineChange(_onManual)
73
+ onImageEngineChange(_onManual)
web/runtime.js CHANGED
@@ -18,7 +18,7 @@ const loadStr = (k) => { try { return localStorage.getItem(k) || '' } catch { re
18
  let activeId = (() => {
19
  const saved = loadStr(ENGINE_KEY)
20
  const e = ENGINES.find((x) => x.id === saved)
21
- return e && e.available() ? saved : (webllm.available() ? 'webllm' : 'wllama')
22
  })()
23
  const modelSel = loadJSON(MODELS_KEY, {}) // engineId -> chosen model id (remembered per engine)
24
 
 
18
  let activeId = (() => {
19
  const saved = loadStr(ENGINE_KEY)
20
  const e = ENGINES.find((x) => x.id === saved)
21
+ return e && e.available() ? saved : 'server'
22
  })()
23
  const modelSel = loadJSON(MODELS_KEY, {}) // engineId -> chosen model id (remembered per engine)
24
 
web/tts.js CHANGED
@@ -3,7 +3,7 @@
3
  // reader that speaks sentence-by-sentence so a war diary can narrate itself while the
4
  // LLM is still writing. Panels + the TTS bar import only from here.
5
  import { engine as kokoro } from '/web/ttsKokoro.js'
6
- import { engine as qwen3, engineLocal as qwen3local, isLocalhost } from '/web/ttsQwen3.js'
7
  import { engine as voxcpm } from '/web/ttsVoxcpm.js'
8
  import { engine as kitten } from '/web/ttsKitten.js'
9
  import { engine as webspeech } from '/web/ttsWebSpeech.js'
@@ -19,7 +19,7 @@ let activeId = (() => {
19
  let saved = ''
20
  try { saved = localStorage.getItem(TTS_ENGINE_KEY) || '' } catch { /* ignore */ }
21
  const e = ENGINES.find((x) => x.id === saved)
22
- return e && e.available() ? saved : (isLocalhost() ? 'qwen3local' : 'kokoro')
23
  })()
24
 
25
  // Qwen3-TTS designs a voice from a free-form description (the persona's `voice`).
 
3
  // reader that speaks sentence-by-sentence so a war diary can narrate itself while the
4
  // LLM is still writing. Panels + the TTS bar import only from here.
5
  import { engine as kokoro } from '/web/ttsKokoro.js'
6
+ import { engine as qwen3, engineLocal as qwen3local } from '/web/ttsQwen3.js'
7
  import { engine as voxcpm } from '/web/ttsVoxcpm.js'
8
  import { engine as kitten } from '/web/ttsKitten.js'
9
  import { engine as webspeech } from '/web/ttsWebSpeech.js'
 
19
  let saved = ''
20
  try { saved = localStorage.getItem(TTS_ENGINE_KEY) || '' } catch { /* ignore */ }
21
  const e = ENGINES.find((x) => x.id === saved)
22
+ return e && e.available() ? saved : 'voxcpm'
23
  })()
24
 
25
  // Qwen3-TTS designs a voice from a free-form description (the persona's `voice`).