client / static /js /settings.js
P01yH3dr0n's picture
launch
774fe36
Raw
History Blame Contribute Delete
13.1 kB
/* ===== Settings Page ===== */
window.NAISettings = {
STORAGE_KEY: 'nai_settings',
// Default values
defaults: {
// General
theme: 'system', // 'light' | 'dark' | 'system'
freeOnly: false,
// Generate defaults
genPrompt: '',
genQuality: 'best quality, amazing quality, very aesthetic, absurdres',
genNegative: 'lowres, {bad}, error, fewer, extra, missing, worst quality, jpeg artifacts, bad quality, watermark, unfinished, displeasing, chromatic aberration, signature, extra digits, artistic error, username, scan, [abstract]',
genSampler: 'k_euler',
genCfg: 5,
genSteps: 28,
genWidth: 1024,
genHeight: 1024,
genScheduler: 'karras',
genSmea: false,
genSmeaDyn: false,
genVariety: false,
genLegacy: false,
genDecrisp: false,
genCfgRescale: 0,
// History
clearHistoryOnRefresh: true,
// Cloud
saveToCloud: true,
// Tag autocomplete
tacEnabled: true,
tacShowZh: true,
tacMatchZh: true,
tacMaxResults: 20,
tacAutoCorrect: true,
tacAddComma: true,
tacChineseComma: false,
tacUnderscoreToSpace: true,
},
current: {},
load() {
try {
const stored = localStorage.getItem(this.STORAGE_KEY);
const parsed = stored ? JSON.parse(stored) : {};
this.current = { ...this.defaults, ...parsed };
} catch (e) {
this.current = { ...this.defaults };
}
},
save() {
try {
localStorage.setItem(this.STORAGE_KEY, JSON.stringify(this.current));
} catch (e) {
console.error('Failed to save settings:', e);
}
},
get(key) {
return this.current[key] ?? this.defaults[key];
},
set(key, value) {
this.current[key] = value;
this.save();
},
// ── Apply settings to UI ──
applyAll() {
this.applyTheme();
this.applyGenerateDefaults();
this.applyCloudCheckbox();
this.applyHistoryClear();
},
applyTheme() {
const theme = this.get('theme');
let effective;
if (theme === 'system') {
effective = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
} else {
effective = theme;
}
document.documentElement.setAttribute('data-theme', effective);
NAIState.theme = effective;
},
applyGenerateDefaults() {
const s = this.current;
const setVal = (id, val) => {
const el = document.getElementById(id);
if (!el) return;
el.value = val;
el.dispatchEvent(new Event('input', { bubbles: true }));
};
const setCheck = (id, val) => {
const el = document.getElementById(id);
if (el) el.checked = !!val;
};
// Only apply defaults if prompt is empty (first load)
const promptEl = $('#prompt-input');
if (promptEl && promptEl.value === '' && s.genPrompt) {
promptEl.value = s.genPrompt;
NAIUtils.autoResize(promptEl);
}
const qualEl = $('#quality-input');
if (qualEl && s.genQuality !== undefined) {
// Always apply quality default on load
if (qualEl.value === this.defaults.genQuality || qualEl.value === '') {
qualEl.value = s.genQuality;
NAIUtils.autoResize(qualEl);
}
}
const negEl = $('#negative-input');
if (negEl && s.genNegative !== undefined) {
if (negEl.value === this.defaults.genNegative || negEl.value === '') {
negEl.value = s.genNegative;
NAIUtils.autoResize(negEl);
}
}
// Sampler
const samplerEl = $('#sampler-select');
if (samplerEl && s.genSampler) {
const opts = [...samplerEl.options].map(o => o.value);
if (opts.includes(s.genSampler)) samplerEl.value = s.genSampler;
}
setVal('cfg-slider', s.genCfg);
setVal('steps-slider', s.genSteps);
setVal('width-slider', s.genWidth);
setVal('height-slider', s.genHeight);
// Advanced
const schedEl = $('#adv-scheduler');
if (schedEl && s.genScheduler) {
const opts = [...schedEl.options].map(o => o.value);
if (opts.includes(s.genScheduler)) schedEl.value = s.genScheduler;
}
setCheck('adv-smea', s.genSmea);
setCheck('adv-smea-dyn', s.genSmeaDyn);
setCheck('adv-variety', s.genVariety);
setCheck('adv-legacy', s.genLegacy);
setCheck('adv-decrisp', s.genDecrisp);
setVal('adv-cfg-rescale', s.genCfgRescale);
},
applyCloudCheckbox() {
const el = $('#save-to-cloud');
if (el) el.checked = this.get('saveToCloud');
},
applyHistoryClear() {
if (this.get('clearHistoryOnRefresh')) {
NAIIDB.clearAllHistory().catch(() => {});
}
},
// ── Capture current generate params as defaults ──
captureCurrentAsDefaults() {
const s = this.current;
s.genPrompt = $('#prompt-input')?.value || '';
s.genQuality = $('#quality-input')?.value || '';
s.genNegative = $('#negative-input')?.value || '';
s.genSampler = $('#sampler-select')?.value || 'k_euler';
s.genCfg = parseFloat($('#cfg-slider')?.value) || 5;
s.genSteps = parseInt($('#steps-slider')?.value) || 28;
s.genWidth = parseInt($('#width-slider')?.value) || 1024;
s.genHeight = parseInt($('#height-slider')?.value) || 1024;
s.genScheduler = $('#adv-scheduler')?.value || 'karras';
s.genSmea = $('#adv-smea')?.checked || false;
s.genSmeaDyn = $('#adv-smea-dyn')?.checked || false;
s.genVariety = $('#adv-variety')?.checked || false;
s.genLegacy = $('#adv-legacy')?.checked || false;
s.genDecrisp = $('#adv-decrisp')?.checked || false;
s.genCfgRescale = parseFloat($('#adv-cfg-rescale')?.value) || 0;
this.save();
},
// ── Render settings page ──
renderPage() {
const s = this.current;
// Theme
$('#setting-theme').value = s.theme;
$('#setting-free-only').checked = s.freeOnly;
// Generate
$('#setting-gen-prompt').value = s.genPrompt;
$('#setting-gen-quality').value = s.genQuality;
$('#setting-gen-negative').value = s.genNegative;
$('#setting-gen-sampler').value = s.genSampler;
$('#setting-gen-cfg').value = s.genCfg;
$('#setting-gen-cfg-val').textContent = parseFloat(s.genCfg).toFixed(1);
$('#setting-gen-steps').value = s.genSteps;
$('#setting-gen-steps-val').textContent = s.genSteps;
$('#setting-gen-width').value = s.genWidth;
$('#setting-gen-width-val').textContent = s.genWidth;
$('#setting-gen-height').value = s.genHeight;
$('#setting-gen-height-val').textContent = s.genHeight;
$('#setting-gen-scheduler').value = s.genScheduler;
$('#setting-gen-smea').checked = s.genSmea;
$('#setting-gen-smea-dyn').checked = s.genSmeaDyn;
$('#setting-gen-variety').checked = s.genVariety;
$('#setting-gen-legacy').checked = s.genLegacy;
$('#setting-gen-decrisp').checked = s.genDecrisp;
$('#setting-gen-cfg-rescale').value = s.genCfgRescale;
$('#setting-gen-cfg-rescale-val').textContent = parseFloat(s.genCfgRescale).toFixed(2);
// History
$('#setting-clear-history').checked = s.clearHistoryOnRefresh;
// Cloud
$('#setting-save-cloud').checked = s.saveToCloud;
// TAC
$('#setting-tac-enabled').checked = s.tacEnabled;
$('#setting-tac-show-zh').checked = s.tacShowZh;
$('#setting-tac-match-zh').checked = s.tacMatchZh;
$('#setting-tac-max').value = s.tacMaxResults;
$('#setting-tac-autocorrect').checked = s.tacAutoCorrect;
$('#setting-tac-add-comma').checked = s.tacAddComma;
$('#setting-tac-zh-comma').checked = s.tacChineseComma;
$('#setting-tac-underscore').checked = s.tacUnderscoreToSpace;
// Auto-resize textareas
$$('#page-settings .form-textarea').forEach(t => NAIUtils.autoResize(t));
},
// ── Bind all settings inputs ──
_bindInputs() {
const bind = (id, key, type = 'value') => {
const el = $(`#${id}`);
if (!el) return;
const event = el.type === 'checkbox' ? 'change' : 'input';
el.addEventListener(event, () => {
let val;
if (type === 'check') val = el.checked;
else if (type === 'float') val = parseFloat(el.value);
else if (type === 'int') val = parseInt(el.value);
else val = el.value;
this.set(key, val);
this._onSettingChanged(key, val);
});
};
// General
bind('setting-theme', 'theme');
bind('setting-free-only', 'freeOnly', 'check');
// Generate
bind('setting-gen-prompt', 'genPrompt');
bind('setting-gen-quality', 'genQuality');
bind('setting-gen-negative', 'genNegative');
bind('setting-gen-sampler', 'genSampler');
bind('setting-gen-cfg', 'genCfg', 'float');
bind('setting-gen-steps', 'genSteps', 'int');
bind('setting-gen-width', 'genWidth', 'int');
bind('setting-gen-height', 'genHeight', 'int');
bind('setting-gen-scheduler', 'genScheduler');
bind('setting-gen-smea', 'genSmea', 'check');
bind('setting-gen-smea-dyn', 'genSmeaDyn', 'check');
bind('setting-gen-variety', 'genVariety', 'check');
bind('setting-gen-legacy', 'genLegacy', 'check');
bind('setting-gen-decrisp', 'genDecrisp', 'check');
bind('setting-gen-cfg-rescale', 'genCfgRescale', 'float');
// History
bind('setting-clear-history', 'clearHistoryOnRefresh', 'check');
// Cloud
bind('setting-save-cloud', 'saveToCloud', 'check');
// TAC
bind('setting-tac-enabled', 'tacEnabled', 'check');
bind('setting-tac-show-zh', 'tacShowZh', 'check');
bind('setting-tac-match-zh', 'tacMatchZh', 'check');
bind('setting-tac-max', 'tacMaxResults', 'int');
bind('setting-tac-autocorrect', 'tacAutoCorrect', 'check');
bind('setting-tac-add-comma', 'tacAddComma', 'check');
bind('setting-tac-zh-comma', 'tacChineseComma', 'check');
bind('setting-tac-underscore', 'tacUnderscoreToSpace', 'check');
// Slider value displays
NAIUtils.bindSlider('setting-gen-cfg', 'setting-gen-cfg-val', v => v.toFixed(1));
NAIUtils.bindSlider('setting-gen-steps', 'setting-gen-steps-val');
NAIUtils.bindSlider('setting-gen-width', 'setting-gen-width-val');
NAIUtils.bindSlider('setting-gen-height', 'setting-gen-height-val');
NAIUtils.bindSlider('setting-gen-cfg-rescale', 'setting-gen-cfg-rescale-val', v => v.toFixed(2));
// Capture button
$('#btn-setting-capture').addEventListener('click', () => {
this.captureCurrentAsDefaults();
this.renderPage();
alert('已将当前参数设为默认值');
});
$('#btn-setting-reset').addEventListener('click', () => {
if (!confirm('确定要重置所有设置吗?')) return;
localStorage.removeItem(this.STORAGE_KEY);
this.load();
this.applyAll();
this.renderPage();
});
$('#btn-tac-cache-refresh').addEventListener('click', () => {
caches.delete('nai-tac-v2');
NAITagComplete.loaded = false;
NAITagComplete.loadTags();
alert('标签自动补全缓存已刷新');
});
},
_onSettingChanged(key, value) {
if (key === 'theme') this.applyTheme();
if (key === 'saveToCloud') this.applyCloudCheckbox();
if (key === 'freeOnly') this._updateFreeOnlyState();
},
_updateFreeOnlyState() {
// This is checked by cost.js when updating buttons
// Force a cost recalc
if (window.NAICost) NAICost.updateCostDisplay();
},
init() {
this.load();
this._bindInputs();
// Render when switching to settings page
document.querySelector('.nav-item[data-page="settings"]')?.addEventListener('click', () => {
this.renderPage();
});
// System theme listener
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
if (this.get('theme') === 'system') this.applyTheme();
});
// Apply settings after a short delay (let other modules init first)
setTimeout(() => this.applyAll(), 100);
},
};