feat: prefill whisper-server models from gguf cache

parent 4b3c6e93
...@@ -970,6 +970,7 @@ async function loadCacheStats(){ ...@@ -970,6 +970,7 @@ async function loadCacheStats(){
} }
let _localModels = []; let _localModels = [];
let _ggufFiles = [];
function _renderWhisperServerRows(models){ function _renderWhisperServerRows(models){
if(!models.length) return ''; if(!models.length) return '';
...@@ -1022,6 +1023,34 @@ function _renderWhisperServerRows(models){ ...@@ -1022,6 +1023,34 @@ function _renderWhisperServerRows(models){
'<th></th></tr></thead><tbody>'+rows.join('')+'</tbody></table></div>'; '<th></th></tr></thead><tbody>'+rows.join('')+'</tbody></table></div>';
} }
function refreshWhisperGgufOptions(){
const ggufSelect = document.getElementById('ws-gguf-select');
if(!ggufSelect) return;
const selectedValue = ggufSelect.value;
ggufSelect.innerHTML = '<option value="">Select downloaded GGUF</option>'+
_ggufFiles.map(f=>`<option value="${esc(f.path)}">${esc(f.filename)}</option>`).join('');
if(selectedValue && _ggufFiles.some(f => f.path === selectedValue)){
ggufSelect.value = selectedValue;
}
}
function prefillWhisperServerFromGguf(path){
const sourceSelect = document.getElementById('ws-model-source');
const ggufSelect = document.getElementById('ws-gguf-select');
const builder = document.getElementById('ws-model-builder');
if(sourceSelect){
sourceSelect.value = 'cached-gguf';
}
toggleWhisperModelSource();
refreshWhisperGgufOptions();
if(ggufSelect){
ggufSelect.value = path;
}
if(builder){
builder.scrollIntoView({behavior:'smooth', block:'start'});
}
}
async function loadCachedModels(){ async function loadCachedModels(){
_localModels = []; _localModels = [];
const hfEl = document.getElementById('hf-models-list'); const hfEl = document.getElementById('hf-models-list');
...@@ -1075,11 +1104,8 @@ async function loadCachedModels(){ ...@@ -1075,11 +1104,8 @@ async function loadCachedModels(){
// GGUF files // GGUF files
const gguf = d.gguf||[]; const gguf = d.gguf||[];
const ggufSelect = document.getElementById('ws-gguf-select'); _ggufFiles = gguf;
if(ggufSelect){ refreshWhisperGgufOptions();
ggufSelect.innerHTML = '<option value="">Select downloaded GGUF</option>'+
gguf.map(f=>`<option value="${esc(f.path)}">${esc(f.filename)}</option>`).join('');
}
document.getElementById('gguf-file-badge').textContent = gguf.length ? `(${gguf.length})` : ''; document.getElementById('gguf-file-badge').textContent = gguf.length ? `(${gguf.length})` : '';
if(!gguf.length){ if(!gguf.length){
ggufEl.innerHTML = '<span class="muted small">No GGUF files cached.</span>'; ggufEl.innerHTML = '<span class="muted small">No GGUF files cached.</span>';
...@@ -1100,6 +1126,7 @@ async function loadCachedModels(){ ...@@ -1100,6 +1126,7 @@ async function loadCachedModels(){
${f.in_config?(loaded ${f.in_config?(loaded
?`<button class="btn btn-ghost btn-sm" onclick="unloadModel(${idx})">Unload</button>` ?`<button class="btn btn-ghost btn-sm" onclick="unloadModel(${idx})">Unload</button>`
:`<button class="btn btn-primary btn-sm" onclick="loadModel(${idx})">Load now</button>`):''} :`<button class="btn btn-primary btn-sm" onclick="loadModel(${idx})">Load now</button>`):''}
<button class="btn btn-secondary btn-sm" onclick="prefillWhisperServerFromGguf('${esc(f.path)}')">Use with whisper-server</button>
<button class="btn btn-secondary btn-sm" onclick="openCfgModal(${idx})">${f.in_config?'Configure':'Add to CoderAI'}</button> <button class="btn btn-secondary btn-sm" onclick="openCfgModal(${idx})">${f.in_config?'Configure':'Add to CoderAI'}</button>
${f.in_config?`<button class="btn btn-ghost btn-sm" onclick="disableModel(${idx})">Remove</button>`:''} ${f.in_config?`<button class="btn btn-ghost btn-sm" onclick="disableModel(${idx})">Remove</button>`:''}
<button class="btn btn-danger btn-sm" onclick="deleteModelConfirm(${idx})">Delete</button> <button class="btn btn-danger btn-sm" onclick="deleteModelConfirm(${idx})">Delete</button>
......
...@@ -428,6 +428,21 @@ def test_models_template_defines_whisper_server_source_toggle_behavior(): ...@@ -428,6 +428,21 @@ def test_models_template_defines_whisper_server_source_toggle_behavior():
assert "modelPath.style.display = useCached ? 'none' : '';" in template assert "modelPath.style.display = useCached ? 'none' : '';" in template
def test_models_template_defines_whisper_server_gguf_prefill_helpers():
template = Path("codai/admin/templates/models.html").read_text()
assert "function refreshWhisperGgufOptions()" in template
assert "function prefillWhisperServerFromGguf(path)" in template
assert "prefillWhisperServerFromGguf(path)" in template
def test_models_template_adds_use_with_whisper_server_gguf_action():
template = Path("codai/admin/templates/models.html").read_text()
assert "Use with whisper-server" in template
assert "onclick=\"prefillWhisperServerFromGguf('${esc(f.path)}')\"" in template
def test_settings_template_no_longer_contains_whisper_server_section(): def test_settings_template_no_longer_contains_whisper_server_section():
template = Path("codai/admin/templates/settings.html").read_text() template = Path("codai/admin/templates/settings.html").read_text()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment