/* Original Deck UI, inspired by LocalAI's explore/detail/download workflow. */
window.CatalogUI = (() => {
const escape = value => String(value ?? '').replace(/[&<>"']/g, c => ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]));
const size = n => { if (!Number.isFinite(n)) return 'Unbekannt'; if(n < 1024) return n+' B'; const unit = n >= 1024**3 ? 'GiB' : n >= 1024**2 ? 'MiB' : 'KiB'; return (n / (unit === 'GiB' ? 1024**3 : unit === 'MiB' ? 1024**2 : 1024)).toFixed(1)+' '+unit; };
const number = n => Number.isFinite(n) ? new Intl.NumberFormat('de-DE', {notation:'compact'}).format(n) : '–';
async function api(path, data) {
const response = await fetch('/api/v1/catalog'+path, data ? {method:'POST',headers:{'Content-Type':'application/json','X-Athena-Deck':'1'},body:JSON.stringify(data)} : {});
const result = await response.json(); if (!response.ok) throw Error(result.error || 'Anfrage fehlgeschlagen'); return result;
}
function html(library, downloads=false) {
return `
HUGGING FACE · LIVE-KATALOG
${downloads ? 'Downloads' : library ? 'Deine Dateien auf Athena' : 'Das nächste Modell entdecken'}
${downloads ? 'Abgeschlossene Einträge ausblenden. Die Dateien bleiben in deiner Bibliothek.' : library ? 'Heruntergeladene Dateien mit festgehaltener Version und Integritätsprüfung.' : 'Modell suchen, Variante vergleichen und gezielt auf Athena herunterladen.'}
${downloads ? '' : library ? '' : `
Beliebte Modelle
01 ENTDECKEN → 02 AUSWÄHLEN → 03 LADEN
Welches Modell interessiert dich?
Wähle ein Ergebnis, um Dateien, Varianten und Lizenz zu prüfen.
Downloads belegen Festplattenspeicher. Sie starten kein Modell. Für Bild, Audio und Video sind häufig mehrere Dateien und ein passender Worker erforderlich.
`}`;
}
function bind(kind, library, downloads=false) {
const root = document.querySelector('#live-catalog'); if (!root) return;
const el = id => root.querySelector('#'+id);
let state = {entries:[],job:null,free_bytes:null,downloads:[]}, models = [], selected = null, detail = null, timer, refreshing = false, searchSequence = 0, detailSequence = 0, starting = false, libraryRendered = false, lastJobs = null;
const message = text => { if (root.isConnected) el('hub-message').textContent = text; };
const fitText = a => a ? `${a.label}${a.weights_fit_now===true?' · Aktuell: Gewichte passen':a.weights_fit_now===false?' · Aktuell: keine GPU mit genug freiem Speicher für diese Datei':''}` : 'Größe und Speicher werden ermittelt …';
const installed = file => detail && state.entries.some(x => x.repo === detail.repo && x.revision === detail.revision && x.file === file.name);
function renderModels() {
const sorted = [...models].sort(el('hub-sort').value === 'name' ? (a,b) => a.repo.localeCompare(b.repo) : (a,b) => (b.downloads||0)-(a.downloads||0));
el('hub-count').textContent = `${models.length} Ergebnisse · höchstens 20 pro Suche`;
el('hub-results').innerHTML = sorted.map(m => ``).join('') || '
Keine Treffer
Versuche einen anderen Namen. Die Suche ist auf den aktuellen Bereich begrenzt.
Dieses Repository benötigt eine Freigabe. Downloads mit Hugging-Face-Zugangsdaten werden noch nicht unterstützt.
' : ''}
Variante oder Datei auswählen
Einzeldatei-Download auf Athena. Geteilte Modelle und Bild-/Audio-/Video-Pipelines benötigen weitere Dateien; dies installiert noch keinen vollständigen Worker.