| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| (function (global) { |
| 'use strict'; |
|
|
| var STATE = { cache: null, inflight: null }; |
|
|
| function fetchEnabledModels(force) { |
| if (!force && STATE.cache) return Promise.resolve(STATE.cache); |
| if (STATE.inflight) return STATE.inflight; |
| STATE.inflight = fetch('/api/enabled-models', { credentials: 'include' }) |
| .then(function (r) { |
| if (!r.ok) throw new Error('HTTP ' + r.status); |
| return r.json(); |
| }) |
| .then(function (data) { |
| STATE.cache = { |
| models: Array.isArray(data.models) ? data.models : [], |
| default_analysis_model: data.default_analysis_model || '', |
| default_answer_model: data.default_answer_model || '', |
| }; |
| return STATE.cache; |
| }) |
| .finally(function () { STATE.inflight = null; }); |
| return STATE.inflight; |
| } |
|
|
| function escapeHtml(s) { |
| return String(s == null ? '' : s).replace(/[&<>"']/g, function (m) { |
| return { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[m]; |
| }); |
| } |
|
|
| function displayName(name, strip) { |
| if (!name) return ''; |
| return (strip !== false && name.indexOf('gemini:') === 0) ? name.substring(7) : name; |
| } |
|
|
| function buildHtml(models, opts) { |
| var parts = []; |
| if (opts.placeholder) { |
| parts.push('<option value="">' + escapeHtml(opts.placeholder) + '</option>'); |
| } |
| if (opts.includeAll) { |
| parts.push('<option value="all">โจ ์ ์ฒด ๋ชจ๋ธ (๋ชจ๋ ๊ณต๊ฐ ์น์์ค)</option>'); |
| } |
| var gemini = models.filter(function (m) { return m.type === 'gemini'; }); |
| var ollama = models.filter(function (m) { return m.type === 'ollama'; }); |
| var etc = models.filter(function (m) { return m.type !== 'gemini' && m.type !== 'ollama'; }); |
|
|
| function group(label, list) { |
| if (!list.length) return; |
| parts.push('<optgroup label="' + escapeHtml(label) + '">'); |
| list.forEach(function (m) { |
| parts.push('<option value="' + escapeHtml(m.name) + '">' + |
| escapeHtml(displayName(m.name, opts.strip)) + '</option>'); |
| }); |
| parts.push('</optgroup>'); |
| } |
| group('โจ Gemini', gemini); |
| group('๐ค Ollama', ollama); |
| group('๊ธฐํ', etc); |
| return parts.join(''); |
| } |
|
|
| |
| |
| |
| |
| function populate(selectEl, opts) { |
| opts = opts || {}; |
| if (!selectEl) return Promise.resolve(null); |
|
|
| var prevPlaceholder = selectEl.innerHTML; |
| selectEl.disabled = true; |
| if (!selectEl.dataset.soyOriginalPlaceholder) { |
| selectEl.innerHTML = '<option value="">' + escapeHtml(opts.loadingText || '๋ชจ๋ธ ๋ชฉ๋ก์ ๋ถ๋ฌ์ค๋ ์คโฆ') + '</option>'; |
| } |
|
|
| return fetchEnabledModels(opts.force).then(function (data) { |
| |
| var models = data.models; |
| if (Array.isArray(opts.typeFilter) && opts.typeFilter.length) { |
| models = models.filter(function (m) { return opts.typeFilter.indexOf(m.type) !== -1; }); |
| } |
| var html = ''; |
| if (!models.length) { |
| html = '<option value="">ํ์ฑํ๋ AI ๋ชจ๋ธ์ด ์์ต๋๋ค (๊ด๋ฆฌ > AI ์ค์ )</option>'; |
| selectEl.innerHTML = html; |
| selectEl.disabled = false; |
| return null; |
| } |
| html = buildHtml(models, opts); |
| selectEl.innerHTML = html; |
|
|
| |
| var fallbackKey = (opts.kind === 'analysis') ? 'default_analysis_model' : 'default_answer_model'; |
| var candidates = [opts.preset, data[fallbackKey]].filter(Boolean); |
| var chosen = null; |
| for (var i = 0; i < candidates.length; i++) { |
| if (models.some(function (m) { return m.name === candidates[i]; })) { |
| chosen = candidates[i]; |
| break; |
| } |
| } |
| if (!chosen && opts.includeAll) chosen = 'all'; |
| if (chosen) selectEl.value = chosen; |
| else if (!opts.placeholder && selectEl.options.length > 0) { |
| |
| for (var j = 0; j < selectEl.options.length; j++) { |
| if (selectEl.options[j].value) { selectEl.value = selectEl.options[j].value; break; } |
| } |
| chosen = selectEl.value || null; |
| } |
|
|
| selectEl.disabled = false; |
| if (typeof opts.onChange === 'function' && chosen) { |
| try { opts.onChange(chosen); } catch (e) { } |
| } |
| return chosen; |
| }).catch(function (err) { |
| console.warn('[SoyEnabledModels] ๋ก๋ ์คํจ:', err); |
| selectEl.innerHTML = prevPlaceholder.indexOf('option') === -1 |
| ? '<option value="">๋ชจ๋ธ ๋ชฉ๋ก ๋ก๋ ์คํจ</option>' |
| : prevPlaceholder; |
| selectEl.disabled = false; |
| return null; |
| }); |
| } |
|
|
| |
| function populateAll(targets) { |
| return fetchEnabledModels().then(function () { |
| return Promise.all((targets || []).map(function (t) { |
| return populate(t.element, t.options || {}); |
| })); |
| }); |
| } |
|
|
| function refresh() { |
| STATE.cache = null; |
| return fetchEnabledModels(true); |
| } |
|
|
| global.SoyEnabledModels = { |
| populate: populate, |
| populateAll: populateAll, |
| fetch: fetchEnabledModels, |
| refresh: refresh, |
| }; |
| })(window); |
|
|