Spaces:
Running
Running
| /** | |
| * Main application bootstrap | |
| * Initializes the WebGPU model loading and wires up event handlers | |
| */ | |
| import { | |
| setupEventListeners, | |
| populateModelSelector, | |
| toggleModelSection, | |
| updateLoadingProgress, | |
| showLoadingProgress, | |
| showModelInputWrapper, | |
| updateModelStatus, | |
| updateWebGPUStatus, | |
| setLoadModelButtonEnabled, | |
| getSelectedModelId, | |
| updateButtonStates, | |
| updateCacheInfo, | |
| setupClearCacheHandler, | |
| setClearCacheButtonText | |
| } from './ui.js'; | |
| import { | |
| generate, | |
| loadModel, | |
| isModelLoaded, | |
| getCurrentModelId, | |
| clearImageCache, | |
| clearModelCache, | |
| getCacheInfo | |
| } from './infer.js'; | |
| import { getAvailableModels, getModelConfig } from './config.js'; | |
| /** | |
| * Handle loading a model | |
| */ | |
| async function handleLoadModel() { | |
| const modelId = getSelectedModelId(); | |
| if (!modelId) { | |
| updateModelStatus('Please select a model', 'error'); | |
| return; | |
| } | |
| // Stop capturing if active (prevents crash) | |
| if (window.stopLiveCaption) { | |
| window.stopLiveCaption(); | |
| } | |
| // Clear image cache when loading a new model | |
| clearImageCache(); | |
| setLoadModelButtonEnabled(false); | |
| showModelInputWrapper(false); | |
| showLoadingProgress(true); | |
| updateButtonStates(false); // Disable Start button while loading | |
| updateModelStatus('Loading model, will take a few minutes if not cached...', 'loading'); | |
| try { | |
| await loadModel(modelId, { | |
| progressCallback: (progress) => { | |
| if (progress.status === 'loading') { | |
| const percent = Math.round(progress.progress || 0); | |
| updateLoadingProgress(percent); | |
| // Show file download progress (includes MB downloaded / total) | |
| const statusText = progress.file | |
| ? `Downloading: ${progress.file}` | |
| : 'Loading model...'; | |
| updateModelStatus(statusText, 'loading'); | |
| } else if (progress.status === 'done') { | |
| updateLoadingProgress(100); | |
| } | |
| } | |
| }); | |
| showLoadingProgress(false); | |
| showModelInputWrapper(true); | |
| const modelConfig = getModelConfig(modelId); | |
| const modelLabel = modelConfig ? `LFM2-VL-450M ${modelConfig.label}` : modelId; | |
| updateModelStatus(`Loaded ${modelLabel}`, 'success'); | |
| updateButtonStates(true); | |
| await refreshCacheInfo(); | |
| } catch (error) { | |
| console.error('Model loading error:', error); | |
| if (error.message && error.message.includes('already loading')) { | |
| updateModelStatus('Model loading in progress...', 'loading'); | |
| return; | |
| } | |
| showLoadingProgress(false); | |
| showModelInputWrapper(true); | |
| updateModelStatus(`Error: ${error.message}`, 'error'); | |
| updateButtonStates(false); | |
| } finally { | |
| setLoadModelButtonEnabled(true); | |
| } | |
| } | |
| /** | |
| * Handle reloading the current model | |
| */ | |
| async function handleReloadModel() { | |
| const currentModelId = getCurrentModelId(); | |
| if (!currentModelId) { | |
| updateModelStatus('No model loaded', 'error'); | |
| return; | |
| } | |
| await handleLoadModel(); | |
| } | |
| /** | |
| * Update cache storage info display | |
| */ | |
| async function refreshCacheInfo() { | |
| const info = await getCacheInfo(); | |
| updateCacheInfo(info ? info.used : 0); | |
| } | |
| /** | |
| * Handle clearing the model cache | |
| */ | |
| async function handleClearCache() { | |
| const info = await getCacheInfo(); | |
| const usedMB = info ? (info.used / 1024 / 1024).toFixed(0) : 0; | |
| const confirmed = confirm( | |
| `Delete downloaded model files?\n\n` + | |
| `This will free up ~${usedMB} MB of storage.\n` + | |
| `Models will be re-downloaded next time you load them.` | |
| ); | |
| if (!confirmed) return; | |
| setClearCacheButtonText('Deleting...'); | |
| await clearModelCache(); | |
| setClearCacheButtonText('Clear'); | |
| await refreshCacheInfo(); | |
| updateModelStatus('Downloaded models deleted', 'success'); | |
| } | |
| /** | |
| * Check WebGPU availability | |
| */ | |
| async function checkWebGPU() { | |
| if (!navigator.gpu) { | |
| updateWebGPUStatus('WebGPU not available. Enable at chrome://flags/#enable-unsafe-webgpu', false); | |
| return false; | |
| } | |
| try { | |
| const adapter = await navigator.gpu.requestAdapter(); | |
| if (!adapter) { | |
| updateWebGPUStatus('WebGPU adapter not found', false); | |
| return false; | |
| } | |
| const info = adapter.info || {}; | |
| const desc = info.description || info.vendor || info.architecture || 'Available'; | |
| updateWebGPUStatus(`WebGPU: ${desc}`, true); | |
| return true; | |
| } catch (error) { | |
| updateWebGPUStatus(`WebGPU error: ${error.message}`, false); | |
| return false; | |
| } | |
| } | |
| /** | |
| * Initialize the application | |
| */ | |
| async function init() { | |
| // Populate model selector | |
| populateModelSelector(getAvailableModels()); | |
| // Check WebGPU availability | |
| await checkWebGPU(); | |
| // Set up event listeners | |
| setupEventListeners(null, handleLoadModel, handleReloadModel); | |
| // Set up cache handler | |
| setupClearCacheHandler(handleClearCache); | |
| // Show model section (WebGPU only) | |
| toggleModelSection(true); | |
| // Initialize button states (disabled until model loads) | |
| updateButtonStates(false); | |
| // Initialize cache info display | |
| await refreshCacheInfo(); | |
| } | |
| // Export functions for use by inline script | |
| window.webgpuInit = { | |
| init, | |
| handleLoadModel, | |
| handleReloadModel, | |
| checkWebGPU, | |
| populateModelSelector: () => populateModelSelector(getAvailableModels()), | |
| toggleModelSection, | |
| updateModelStatus, | |
| getCurrentModelId, | |
| isModelLoaded, | |
| getAvailableModels, | |
| generate, | |
| updateButtonStates | |
| }; | |
| // Signal that WebGPU module is ready | |
| window.dispatchEvent(new Event('webgpu-ready')); | |
| // Initialize when DOM is ready | |
| if (document.readyState === 'loading') { | |
| document.addEventListener('DOMContentLoaded', init); | |
| } else { | |
| init(); | |
| } | |