Spaces:
Running
Running
Download src/dashboard/static/frontend/modules/functional-completion.js from ThomasHeisig/MHRN-Space: direct link, hf CLI and curl.
- Browser
- Download file 10.7 kB
-
https://huggingface.co/spaces/ThomasHeisig/MHRN-Space/resolve/main/src/dashboard/static/frontend/modules/functional-completion.js
- Command line
-
hf download hf://spaces/ThomasHeisig/MHRN-Space/src/dashboard/static/frontend/modules/functional-completion.js
-
curl -L -o functional-completion.js https://huggingface.co/spaces/ThomasHeisig/MHRN-Space/resolve/main/src/dashboard/static/frontend/modules/functional-completion.js
10.7 kB
| ; | |
| const VIEWER_PROFILE_KEY = "mhrn.neuron-model-viewer.profile.v1"; | |
| const RATE_REFRESH_MS = 5000; | |
| const EMBODIMENT_REFRESH_MS = 5000; | |
| let initialized = false; | |
| let viewerTimer = null; | |
| let embodimentTimer = null; | |
| let rootObserver = null; | |
| let profileRestored = false; | |
| const byId = (id) => document.getElementById(id); | |
| async function readJson(url) { | |
| const response = await fetch(url, { cache: "no-store", headers: { Accept: "application/json" } }); | |
| const payload = await response.json().catch(() => ({})); | |
| if (!response.ok) throw new Error(payload.error || `HTTP ${response.status}`); | |
| return payload; | |
| } | |
| function finite(value) { | |
| const parsed = Number(value); | |
| return Number.isFinite(parsed) ? parsed : null; | |
| } | |
| function formatRate(value) { | |
| if (!Number.isFinite(value)) return "—"; | |
| if (value >= 100) return `${value.toFixed(1)} Hz`; | |
| if (value >= 10) return `${value.toFixed(2)} Hz`; | |
| return `${value.toFixed(3)} Hz`; | |
| } | |
| function findViewerStat(label) { | |
| return [...document.querySelectorAll("#neuron-model-viewer .nmv-stat")] | |
| .find((node) => node.querySelector("span")?.textContent?.trim() === label) || null; | |
| } | |
| function setProfileStatus(text, title = "") { | |
| const node = byId("nmv-profile-status"); | |
| if (!node) return; | |
| if (node.textContent !== text) node.textContent = text; | |
| node.title = title || "Lokales presentation-only Ansichtsprofil; keine Runtime- oder Evidenzdaten."; | |
| } | |
| function currentViewerProfile() { | |
| return { | |
| version: 1, | |
| method: byId("nmv-method")?.value || "pca", | |
| dimensions: byId("nmv-dim")?.value || "2", | |
| sample: byId("nmv-sample")?.value || "500", | |
| interval: byId("nmv-interval")?.value || "0", | |
| view: document.querySelector("#neuron-model-viewer [data-nmv-view].active")?.dataset.nmvView || "projection", | |
| saved_at: new Date().toISOString(), | |
| scope: "presentation_only", | |
| }; | |
| } | |
| function saveViewerProfile() { | |
| if (!byId("neuron-model-viewer")) return; | |
| try { | |
| const profile = currentViewerProfile(); | |
| localStorage.setItem(VIEWER_PROFILE_KEY, JSON.stringify(profile)); | |
| setProfileStatus("gespeichert · lokal", `Gespeichert ${new Date(profile.saved_at).toLocaleString("de-DE")} · presentation-only`); | |
| } catch (error) { | |
| setProfileStatus("Speicher nicht verfügbar", String(error.message || error)); | |
| } | |
| } | |
| function restoreViewerProfile() { | |
| if (profileRestored || !byId("neuron-model-viewer")) return; | |
| profileRestored = true; | |
| let profile = null; | |
| try { profile = JSON.parse(localStorage.getItem(VIEWER_PROFILE_KEY) || "null"); } catch (_) {} | |
| if (!profile || typeof profile !== "object") { | |
| setProfileStatus("bereit · lokal", "Noch kein Ansichtsprofil gespeichert. Änderungen werden automatisch lokal gespeichert."); | |
| return; | |
| } | |
| const assign = (id, value, emit = true) => { | |
| const control = byId(id); | |
| if (!control || ![...control.options].some((option) => option.value === String(value))) return; | |
| control.value = String(value); | |
| if (emit) control.dispatchEvent(new Event("change", { bubbles: true })); | |
| }; | |
| // Method is restored without firing change: nonlinear backend jobs must never | |
| // start merely because the page was opened. | |
| assign("nmv-method", profile.method || "pca", false); | |
| assign("nmv-dim", profile.dimensions || "2"); | |
| assign("nmv-sample", profile.sample || "500"); | |
| assign("nmv-interval", profile.interval || "0"); | |
| const view = document.querySelector(`#neuron-model-viewer [data-nmv-view="${CSS.escape(String(profile.view || "projection"))}"]`); | |
| view?.click(); | |
| setProfileStatus("wiederhergestellt · lokal", "Presentation-only Ansichtsprofil aus localStorage wiederhergestellt."); | |
| } | |
| function bindViewerProfile(viewer) { | |
| if (viewer.dataset.functionalCompletionBound === "true") return; | |
| viewer.dataset.functionalCompletionBound = "true"; | |
| ["nmv-method", "nmv-dim", "nmv-sample", "nmv-interval"].forEach((id) => { | |
| byId(id)?.addEventListener("change", () => { | |
| saveViewerProfile(); | |
| if (id === "nmv-sample") void refreshNeuronRates(); | |
| }); | |
| }); | |
| viewer.querySelector(".nmv-view-tabs")?.addEventListener("click", (event) => { | |
| if (event.target.closest("[data-nmv-view]")) queueMicrotask(saveViewerProfile); | |
| }); | |
| } | |
| function ensureViewerCompletion() { | |
| const viewer = byId("neuron-model-viewer"); | |
| if (!viewer) return false; | |
| if (viewer.dataset.functionalCompletionReady === "true") return true; | |
| const rateStat = findViewerStat("Per-neuron Hz"); | |
| if (rateStat) { | |
| const label = rateStat.querySelector("span"); | |
| const value = rateStat.querySelector("strong"); | |
| if (label) { | |
| label.textContent = "Per-neuron Hz · kumulativ"; | |
| label.title = "Kumulative Feuerrate seit Runtime-Start; keine Instantanrate."; | |
| } | |
| if (value) { | |
| value.id = "nmv-rate-summary"; | |
| value.classList.remove("nmv-pending"); | |
| value.textContent = "Messfenster wird geladen …"; | |
| } | |
| } | |
| const profileStat = findViewerStat("Profil-Cache"); | |
| if (profileStat) { | |
| const label = profileStat.querySelector("span"); | |
| const value = profileStat.querySelector("strong"); | |
| if (label) { | |
| label.textContent = "Ansichtsprofil"; | |
| label.title = "Presentation-only Zustand des Viewers; keine wissenschaftlichen Daten."; | |
| } | |
| if (value) { | |
| value.id = "nmv-profile-status"; | |
| value.classList.remove("nmv-pending"); | |
| value.textContent = "lokal · presentation-only"; | |
| } | |
| } | |
| const legend = viewer.querySelector(".nmv-legend"); | |
| if (legend) { | |
| const marker = legend.querySelector("i"); | |
| legend.replaceChildren(document.createTextNode("Feuerrate · kumulativ ")); | |
| if (marker) legend.append(marker); | |
| legend.title = "Bei festem Beobachtungsfenster ist die Spike-Counter-Farbskala monoton äquivalent zur kumulativen Feuerrate."; | |
| } | |
| bindViewerProfile(viewer); | |
| restoreViewerProfile(); | |
| viewer.dataset.functionalCompletionReady = "true"; | |
| return true; | |
| } | |
| async function refreshNeuronRates() { | |
| if (!ensureViewerCompletion()) return; | |
| const output = byId("nmv-rate-summary"); | |
| if (!output) return; | |
| const requested = Math.max(1, Math.min(2000, Number(byId("nmv-sample")?.value || 500))); | |
| try { | |
| const [summary, projection] = await Promise.all([ | |
| readJson("/api/network/summary"), | |
| readJson(`/api/network/projection?limit=${requested}&mode=activity`), | |
| ]); | |
| const tick = finite(summary.current_tick); | |
| const dtMs = 1.0; // Reference core invariant: SimulationConfig enforces dt_ms == 1.0. | |
| if (tick === null || tick <= 0) { | |
| output.textContent = "noch kein Messfenster · Tick 0"; | |
| output.title = "Eine Feuerrate benötigt ein positives Beobachtungsfenster."; | |
| return; | |
| } | |
| const durationSeconds = tick * dtMs / 1000; | |
| const rates = (projection.points || []) | |
| .map((point) => finite(point.value)) | |
| .filter((value) => value !== null) | |
| .map((spikeCount) => spikeCount / durationSeconds); | |
| if (!rates.length) { | |
| output.textContent = "keine Neuronendaten"; | |
| return; | |
| } | |
| const mean = rates.reduce((sum, value) => sum + value, 0) / rates.length; | |
| output.textContent = `μ ${formatRate(mean)} · ${formatRate(Math.min(...rates))}–${formatRate(Math.max(...rates))} · n=${rates.length}`; | |
| output.title = `Kumulative Feuerrate über ${tick.toLocaleString("de-DE")} Ticks (${durationSeconds.toFixed(3)} s). Quelle: Live-Runtime. Kein EVIDENCE-Claim.`; | |
| } catch (error) { | |
| output.textContent = `nicht verfügbar · ${error.message}`; | |
| output.title = "Live-Raten konnten nicht aus den Runtime-Endpunkten berechnet werden."; | |
| } | |
| } | |
| function feedbackStatus(pipeline, state) { | |
| if (state?.last_observation_state) return ["observation received", `Rückkopplung gemessen: ${state.last_observation_state}`]; | |
| const stage = pipeline?.stages?.feedback; | |
| if (!stage) return ["state unknown", "Der Pipeline-Vertrag hat keinen Feedback-Status geliefert."]; | |
| if (stage.implemented === false) return ["adapter feedback unavailable", "Die aktuelle Adapter-/Runtime-Konfiguration veröffentlicht keinen implementierten Feedback-Pfad."]; | |
| if (stage.enabled) return ["enabled · waiting for observation", "Feedback-Pipeline ist freigegeben; noch keine EnvironmentObservation empfangen."]; | |
| return ["ready · disabled", "Feedback-Pipeline ist implementiert, aktuell aber deaktiviert."]; | |
| } | |
| async function refreshEmbodimentFeedback() { | |
| const node = byId("embodiment-feedback-state"); | |
| if (!node) return; | |
| try { | |
| const [pipeline, state] = await Promise.all([ | |
| readJson("/api/embodiment/pipeline"), | |
| readJson("/api/embodiment/state"), | |
| ]); | |
| const [text, title] = feedbackStatus(pipeline, state); | |
| if (node.textContent !== text) node.textContent = text; | |
| node.title = title; | |
| node.dataset.functionalState = text.replace(/[^a-z0-9]+/gi, "-").toLowerCase(); | |
| } catch (error) { | |
| if (node.textContent !== "state unavailable") node.textContent = "state unavailable"; | |
| node.title = `Embodiment-Status nicht erreichbar: ${error.message}`; | |
| } | |
| } | |
| function annotateGuardedDisabledControls() { | |
| const experimentStop = byId("experiment-stop"); | |
| if (experimentStop?.disabled && !experimentStop.title) { | |
| experimentStop.title = "Wird automatisch aktiviert, sobald eine Experiment-Session aktiv ist."; | |
| } | |
| document.querySelectorAll("button:disabled, input:disabled, select:disabled, option:disabled").forEach((control) => { | |
| if (!control.title && control.getAttribute("aria-label")) control.title = control.getAttribute("aria-label"); | |
| }); | |
| } | |
| function scanDynamicSurfaces() { | |
| ensureViewerCompletion(); | |
| annotateGuardedDisabledControls(); | |
| } | |
| export function initFunctionalCompletion() { | |
| if (initialized) { | |
| scanDynamicSurfaces(); | |
| void refreshNeuronRates(); | |
| void refreshEmbodimentFeedback(); | |
| return; | |
| } | |
| initialized = true; | |
| scanDynamicSurfaces(); | |
| void refreshNeuronRates(); | |
| void refreshEmbodimentFeedback(); | |
| rootObserver = new MutationObserver(() => { | |
| if (!byId("neuron-model-viewer")?.dataset.functionalCompletionReady) scanDynamicSurfaces(); | |
| }); | |
| rootObserver.observe(document.querySelector("main") || document.body, { childList: true, subtree: true }); | |
| viewerTimer = window.setInterval(refreshNeuronRates, RATE_REFRESH_MS); | |
| embodimentTimer = window.setInterval(refreshEmbodimentFeedback, EMBODIMENT_REFRESH_MS); | |
| window.addEventListener("beforeunload", () => { | |
| if (viewerTimer) clearInterval(viewerTimer); | |
| if (embodimentTimer) clearInterval(embodimentTimer); | |
| rootObserver?.disconnect(); | |
| }, { once: true }); | |
| window.MHRNFunctionalCompletion = { | |
| refresh: () => { | |
| scanDynamicSurfaces(); | |
| void refreshNeuronRates(); | |
| void refreshEmbodimentFeedback(); | |
| }, | |
| viewerProfileKey: VIEWER_PROFILE_KEY, | |
| }; | |
| } | |