Spaces:
Running
Running
| /** | |
| * UI rendering and DOM manipulation | |
| */ | |
| // WebGPU/Model control getters | |
| function getModelSelect() { | |
| return document.getElementById('model-select'); | |
| } | |
| function getLoadModelBtn() { | |
| return document.getElementById('load-model-btn'); | |
| } | |
| function getLoadingProgress() { | |
| return document.getElementById('loading-progress'); | |
| } | |
| function getProgressFill() { | |
| return document.getElementById('progress-fill'); | |
| } | |
| function getProgressText() { | |
| return document.getElementById('progress-text'); | |
| } | |
| function getModelStatus() { | |
| return document.getElementById('model-status'); | |
| } | |
| function getWebGPUStatus() { | |
| return document.getElementById('webgpu-status'); | |
| } | |
| function getModelSection() { | |
| return document.getElementById('model-section'); | |
| } | |
| function getReloadModelBtn() { | |
| return document.getElementById('reload-model-btn'); | |
| } | |
| function getClearCacheBtn() { | |
| return document.getElementById('clear-cache-btn'); | |
| } | |
| function getCacheInfo() { | |
| return document.getElementById('cache-info'); | |
| } | |
| /** | |
| * Populate model selector with available models | |
| * @param {Array} models - Array of model configurations | |
| */ | |
| export function populateModelSelector(models) { | |
| const modelSelect = getModelSelect(); | |
| if (!modelSelect) return; | |
| modelSelect.innerHTML = ''; | |
| models.forEach(model => { | |
| const option = document.createElement('option'); | |
| option.value = model.id; | |
| const noteText = model.note ? ` - ${model.note}` : ''; | |
| option.textContent = `${model.label} (${model.size}${noteText})`; | |
| modelSelect.appendChild(option); | |
| }); | |
| } | |
| /** | |
| * Show/hide model section based on inference mode | |
| * @param {boolean} show - Whether to show the model section | |
| */ | |
| export function toggleModelSection(show) { | |
| const modelSection = getModelSection(); | |
| if (modelSection) { | |
| if (show) { | |
| modelSection.classList.remove('hidden'); | |
| } else { | |
| modelSection.classList.add('hidden'); | |
| } | |
| } | |
| } | |
| /** | |
| * Update loading progress | |
| * @param {number} percent - Progress percentage (0-100), or -1 for indeterminate | |
| */ | |
| export function updateLoadingProgress(percent) { | |
| const progressFill = getProgressFill(); | |
| const progressBar = getLoadingProgress(); | |
| // Handle indeterminate state (percent < 0) | |
| if (progressBar) { | |
| if (percent < 0) { | |
| progressBar.classList.add('indeterminate'); | |
| } else { | |
| progressBar.classList.remove('indeterminate'); | |
| } | |
| } | |
| if (progressFill) { | |
| progressFill.style.width = percent < 0 ? '30%' : `${percent}%`; | |
| } | |
| } | |
| /** | |
| * Show/hide loading progress | |
| * @param {boolean} show - Whether to show the progress bar | |
| */ | |
| export function showLoadingProgress(show) { | |
| const loadingProgress = getLoadingProgress(); | |
| if (loadingProgress) { | |
| loadingProgress.style.display = show ? 'block' : 'none'; | |
| } | |
| } | |
| /** | |
| * Show/hide the model input wrapper (dropdown + load button) | |
| * @param {boolean} show - Whether to show the input wrapper | |
| */ | |
| export function showModelInputWrapper(show) { | |
| const wrapper = document.querySelector('.model-input-wrapper'); | |
| if (wrapper) { | |
| wrapper.style.display = show ? 'flex' : 'none'; | |
| } | |
| } | |
| /** | |
| * Update model status display | |
| * @param {string} message - Status message | |
| * @param {string} type - Status type ('success', 'error', 'loading', or '') | |
| */ | |
| export function updateModelStatus(message, type = '') { | |
| const modelStatus = getModelStatus(); | |
| if (modelStatus) { | |
| modelStatus.textContent = message; | |
| modelStatus.className = 'model-status'; | |
| if (type) { | |
| modelStatus.classList.add(type); | |
| } | |
| modelStatus.style.display = message ? 'block' : 'none'; | |
| } | |
| } | |
| /** | |
| * Update WebGPU status display | |
| * @param {string} message - Status message | |
| * @param {boolean} available - Whether WebGPU is available | |
| */ | |
| export function updateWebGPUStatus(message, available) { | |
| const webgpuStatus = getWebGPUStatus(); | |
| if (webgpuStatus) { | |
| webgpuStatus.textContent = message; | |
| webgpuStatus.className = 'webgpu-status'; | |
| if (available) { | |
| webgpuStatus.classList.add('available'); | |
| } else { | |
| webgpuStatus.classList.add('unavailable'); | |
| } | |
| } | |
| } | |
| /** | |
| * Enable/disable model loading button | |
| * @param {boolean} enabled - Whether to enable the button | |
| */ | |
| export function setLoadModelButtonEnabled(enabled) { | |
| const loadModelBtn = getLoadModelBtn(); | |
| if (loadModelBtn) { | |
| loadModelBtn.disabled = !enabled; | |
| } | |
| } | |
| /** | |
| * Get selected model ID | |
| * @returns {string|null} | |
| */ | |
| export function getSelectedModelId() { | |
| const modelSelect = getModelSelect(); | |
| return modelSelect ? modelSelect.value : null; | |
| } | |
| /** | |
| * Update button states based on model load status | |
| * @param {boolean} modelLoaded - Whether the model is loaded | |
| */ | |
| export function updateButtonStates(modelLoaded) { | |
| const tooltipText = modelLoaded ? '' : 'Load a model first'; | |
| // Update live caption button | |
| const liveCaptionBtn = document.getElementById('start-live-caption-btn'); | |
| if (liveCaptionBtn) { | |
| liveCaptionBtn.disabled = !modelLoaded; | |
| liveCaptionBtn.title = tooltipText; | |
| // Update button text based on model state | |
| if (!modelLoaded) { | |
| liveCaptionBtn.textContent = 'Load Model Below'; | |
| } else { | |
| liveCaptionBtn.textContent = 'Start'; | |
| } | |
| } | |
| } | |
| /** | |
| * Set up event listeners (simplified - only for model loading) | |
| * @param {Function} onSend - Not used (kept for compatibility) | |
| * @param {Function} onLoadModel - Callback for load model button | |
| * @param {Function} onReloadModel - Callback for reload model button | |
| */ | |
| export function setupEventListeners(onSend, onLoadModel, onReloadModel) { | |
| // Load model button | |
| const loadModelBtn = getLoadModelBtn(); | |
| if (loadModelBtn && onLoadModel) { | |
| loadModelBtn.addEventListener('click', onLoadModel); | |
| } | |
| // Reload model button | |
| const reloadModelBtn = getReloadModelBtn(); | |
| if (reloadModelBtn && onReloadModel) { | |
| reloadModelBtn.addEventListener('click', onReloadModel); | |
| } | |
| } | |
| /** | |
| * Update cache info display | |
| * @param {number} usedBytes - Bytes used by cache | |
| */ | |
| export function updateCacheInfo(usedBytes) { | |
| const cacheInfoEl = getCacheInfo(); | |
| const clearCacheBtn = getClearCacheBtn(); | |
| if (!cacheInfoEl) return; | |
| if (usedBytes > 0) { | |
| const usedMB = usedBytes / 1024 / 1024; | |
| if (usedMB >= 1000) { | |
| cacheInfoEl.textContent = `${(usedMB / 1024).toFixed(1)} GB cached`; | |
| } else if (usedMB >= 1) { | |
| cacheInfoEl.textContent = `${usedMB.toFixed(0)} MB cached`; | |
| } else { | |
| cacheInfoEl.textContent = 'No models cached'; | |
| } | |
| if (clearCacheBtn) { | |
| clearCacheBtn.disabled = usedMB < 1; | |
| } | |
| } else { | |
| cacheInfoEl.textContent = 'No models cached'; | |
| if (clearCacheBtn) { | |
| clearCacheBtn.disabled = true; | |
| } | |
| } | |
| } | |
| /** | |
| * Set up clear cache button handler | |
| * @param {Function} onClearCache - Callback for clear cache button | |
| */ | |
| export function setupClearCacheHandler(onClearCache) { | |
| const clearCacheBtn = getClearCacheBtn(); | |
| if (clearCacheBtn && onClearCache) { | |
| clearCacheBtn.addEventListener('click', onClearCache); | |
| } | |
| } | |
| /** | |
| * Set clear cache button text | |
| * @param {string} text - Button text | |
| */ | |
| export function setClearCacheButtonText(text) { | |
| const clearCacheBtn = getClearCacheBtn(); | |
| if (clearCacheBtn) { | |
| clearCacheBtn.textContent = text; | |
| } | |
| } | |