// Real Hugging Face API integration class AssetManager { constructor() { this.assets = []; this.currentId = 0; this.token = null; this.spaceName = null; this.username = null; } async authenticate(token) { this.token = token; try { const response = await fetch('https://huggingface.co/api/whoami-v2', { headers: { 'Authorization': `Bearer ${token}` } }); const userData = await response.json(); this.username = userData.name; return true; } catch (error) { console.error('Authentication failed:', error); return false; } } async loadAssets(spaceName) { this.spaceName = spaceName; try { const response = await fetch(`https://huggingface.co/api/spaces/${this.username}/${spaceName}/files`, { headers: { 'Authorization': `Bearer ${this.token}` } }); const files = await response.json(); this.assets = files.map(file => ({ id: ++this.currentId, name: file.path.split('/').pop(), type: this.getFileType(file.path), url: `https://huggingface.co/spaces/${this.username}/${spaceName}/resolve/main/${file.path}`, preview: this.getPreviewUrl(file.path), path: file.path, lastModified: file.lastModified })); return this.assets; } catch (error) { console.error('Failed to load assets:', error); return []; } } getFileType(filename) { const extension = filename.split('.').pop().toLowerCase(); const types = { 'jpg': 'image/jpeg', 'jpeg': 'image/jpeg', 'png': 'image/png', 'gif': 'image/gif', 'pdf': 'application/pdf', 'txt': 'text/plain', 'csv': 'text/csv', 'json': 'application/json' }; return types[extension] || 'application/octet-stream'; } getPreviewUrl(filename) { const extension = filename.split('.').pop().toLowerCase(); if (['jpg', 'jpeg', 'png', 'gif'].includes(extension)) { return `https://huggingface.co/spaces/${this.username}/${this.spaceName}/preview/${filename}`; } return `http://static.photos/office/320x240/${Math.floor(Math.random() * 100)}`; } async addAsset(file) { const formData = new FormData(); formData.append('file', file); try { const response = await fetch(`https://huggingface.co/api/spaces/${this.username}/${this.spaceName}/upload`, { method: 'POST', headers: { 'Authorization': `Bearer ${this.token}` }, body: formData }); if (response.ok) { const newAsset = { id: ++this.currentId, name: file.name, type: file.type || this.getFileType(file.name), url: `https://huggingface.co/spaces/${this.username}/${this.spaceName}/resolve/main/${file.name}`, preview: this.getPreviewUrl(file.name), path: file.name, lastModified: new Date().toISOString() }; this.assets.push(newAsset); return newAsset; } return null; } catch (error) { console.error('Failed to upload file:', error); return null; } } async updateAsset(id, updates) { const asset = this.assets.find(a => a.id === id); if (!asset) return null; // For Hugging Face, updating means deleting and re-uploading if (updates.file) { await this.deleteAsset(id); return await this.addAsset(updates.file); } else { // For metadata updates const index = this.assets.findIndex(a => a.id === id); this.assets[index] = { ...asset, ...updates }; return this.assets[index]; } } async deleteAsset(id) { const asset = this.assets.find(a => a.id === id); if (!asset) return false; try { const response = await fetch(`https://huggingface.co/api/spaces/${this.username}/${this.spaceName}/delete/${asset.path}`, { method: 'DELETE', headers: { 'Authorization': `Bearer ${this.token}` } }); if (response.ok) { this.assets = this.assets.filter(a => a.id !== id); return true; } return false; } catch (error) { console.error('Failed to delete file:', error); return false; } } getAssets() { return [...this.assets]; } exportAsJSON() { return JSON.stringify(this.assets, null, 2); } } // Main application with authentication class HuggingSpaceApp { constructor() { this.assetManager = new AssetManager(); this.initElements(); this.initEventListeners(); this.checkAuth(); } initElements() { this.elements = { assetsTable: document.getElementById('assetsTable'), uploadBtn: document.getElementById('uploadBtn'), uploadModal: document.getElementById('uploadModal'), closeModal: document.getElementById('closeModal'), fileInput: document.getElementById('fileInput'), confirmUpload: document.getElementById('confirmUpload'), exportBtn: document.getElementById('exportBtn'), jsonData: document.getElementById('jsonData'), authModal: document.getElementById('authModal'), tokenInput: document.getElementById('tokenInput'), spaceInput: document.getElementById('spaceInput'), authSubmit: document.getElementById('authSubmit'), authError: document.getElementById('authError'), userInfo: document.getElementById('userInfo') }; } initEventListeners() { this.elements.uploadBtn.addEventListener('click', () => this.toggleModal(true)); this.elements.closeModal.addEventListener('click', () => this.toggleModal(false)); this.elements.confirmUpload.addEventListener('click', () => this.handleFileUpload()); this.elements.exportBtn.addEventListener('click', () => this.exportData()); this.elements.authSubmit.addEventListener('click', () => this.handleAuth()); } async checkAuth() { const token = localStorage.getItem('hfToken'); const space = localStorage.getItem('hfSpace'); if (token && space) { const authenticated = await this.assetManager.authenticate(token); if (authenticated) { await this.assetManager.loadAssets(space); this.render(); this.elements.authModal.classList.add('hidden'); this.updateUserInfo(); return; } } this.elements.authModal.classList.remove('hidden'); } async handleAuth() { const token = this.elements.tokenInput.value.trim(); const space = this.elements.spaceInput.value.trim(); if (!token || !space) { this.elements.authError.textContent = 'Please enter both token and space name'; return; } const authenticated = await this.assetManager.authenticate(token); if (!authenticated) { this.elements.authError.textContent = 'Invalid token. Please check and try again.'; return; } try { await this.assetManager.loadAssets(space); localStorage.setItem('hfToken', token); localStorage.setItem('hfSpace', space); this.elements.authModal.classList.add('hidden'); this.render(); this.updateUserInfo(); } catch (error) { this.elements.authError.textContent = 'Failed to load space. Please check space name and try again.'; } } updateUserInfo() { if (this.assetManager.username && this.assetManager.spaceName) { this.elements.userInfo.innerHTML = `