"use strict"; const state = { index: 0, total: 0, neuron: null, timer: null, lastSpike: null, lastRuntimeTick: null, inFlight: false, }; const $ = (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(); if (!response.ok) throw new Error(payload.error || `HTTP ${response.status}`); return payload; } function fmt(value, digits = 3) { if (value === null || value === undefined) return "—"; if (typeof value === "number") return Number.isInteger(value) ? String(value) : value.toFixed(digits); return String(value); } function kv(label, value, digits = 3) { return `
${label}${fmt(value, digits)}
`; } function ensurePanel() { const root = $("tab-wesen"); if (!root || $("mhrn-runtime-neuron")) return; const panel = document.createElement("section"); panel.id = "mhrn-runtime-neuron"; panel.className = "card runtime-neuron-panel"; panel.hidden = true; panel.dataset.mhrnRoute = "wesen:neuron"; panel.innerHTML = `
RUNTIME & WESEN · SINGLE CELL

Einzelnes Neuron

Read-only Darstellung eines realen Live-Neurons aus dem laufenden Netzwerk. Keine simulierten UI-Daten.

———
membranev = —threshold = — input / dendritesaxon / output
Membran
—
Energie
—
Threshold Δ
—

Zellzustand

live runtime

Input, Spike & Reset

causal state

Plastizität & Regulation

integrated mechanisms

Modell & Provenienz

versioned
Bereit.
Diese Ansicht ist Beobachtung/Debugging. Sie verändert den Zellzustand nicht und ist kein Beleg biologischer Äquivalenz.
`; root.appendChild(panel); $("rn-prev")?.addEventListener("click", () => setIndex(state.index - 1)); $("rn-next")?.addEventListener("click", () => setIndex(state.index + 1)); $("rn-refresh")?.addEventListener("click", refresh); $("rn-index")?.addEventListener("change", (event) => setIndex(Number(event.target.value))); } function isActiveRoute() { return document.body.dataset.currentArea === "wesen" && document.body.dataset.currentRoute === "neuron"; } function syncPolling() { if (isActiveRoute()) { refresh(); if (!state.timer) { state.timer = setInterval(() => { if (isActiveRoute()) refresh(); }, 750); } return; } if (state.timer) { clearInterval(state.timer); state.timer = null; } } function setIndex(value) { const max = Math.max(0, state.total - 1); state.index = Math.max(0, Math.min(max, Number.isFinite(value) ? Math.trunc(value) : 0)); if ($("rn-index")) $("rn-index").value = String(state.index); refresh(); } function meter(id, labelId, ratio, label) { const fill = $(id); const out = $(labelId); if (fill) fill.style.width = `${Math.max(0, Math.min(100, ratio * 100))}%`; if (out) out.textContent = label; } function render(neuron, total) { state.neuron = neuron; state.total = total; const model = neuron.model || neuron.model_provenance?.id || "unknown"; const maturity = neuron.model_provenance?.canonical ? "canonical" : (model === "lif-current-v1" ? "experimental" : "configured"); $("rn-model").textContent = model; $("rn-model").dataset.state = maturity; $("rn-type").textContent = neuron.neuron_type || "unknown"; const ref = neuron.refractory_active ? "refractory" : (neuron.enabled ? "active" : "disabled"); $("rn-state").textContent = ref; $("rn-state").dataset.state = ref; $("rn-id").value = String(neuron.neuron_id); $("rn-index").max = String(Math.max(0,total-1)); $("rn-index").value = String(state.index); $("rn-visual").dataset.refractory = String(Boolean(neuron.refractory_active)); const spikedNow = neuron.last_spike === neuron.runtime_tick && neuron.last_spike !== state.lastSpike; $("rn-visual").dataset.spiked = String(spikedNow); state.lastSpike = neuron.last_spike; $("rn-svg-v").textContent = `v = ${fmt(neuron.v)} mV`; $("rn-svg-threshold").textContent = `threshold = ${fmt(neuron.current_threshold)} mV`; const threshold = Number(neuron.current_threshold ?? 30); const v = Number(neuron.v ?? -65); meter("rn-v-meter","rn-v-meter-label",(v + 90) / (threshold + 90),`${fmt(v)} mV`); meter("rn-energy-meter","rn-energy-meter-label",Number(neuron.energy ?? 0),fmt(neuron.energy)); meter("rn-threshold-meter","rn-threshold-meter-label",(Number(neuron.threshold_adaptation ?? 0)+10)/20,fmt(neuron.threshold_adaptation)); $("rn-cell-state").innerHTML = [kv("v",neuron.v),kv("u",neuron.u),kv("threshold",neuron.current_threshold),kv("energy",neuron.energy),kv("coordinates",`[${[neuron.x1,neuron.x2,neuron.x3,neuron.x4,neuron.x5].join(", ")}]`),kv("enabled",neuron.enabled)].join(""); $("rn-spike-state").innerHTML = [kv("spike count",neuron.spike_count),kv("last spike tick",neuron.last_spike),kv("refractory",neuron.refractory_active),kv("refractory remaining",neuron.refractory_remaining_ticks),kv("external current",neuron.last_external_current),kv("synaptic current",neuron.last_synaptic_current),kv("input cell",neuron.is_input),kv("output cell",neuron.is_output),kv("runtime tick",neuron.runtime_tick)].join(""); $("rn-learning-state").innerHTML = [kv("threshold adaptation",neuron.threshold_adaptation),kv("pre trace",neuron.pre_trace),kv("post trace",neuron.post_trace),kv("firing-rate estimate",neuron.firing_rate_estimate),kv("homeostasis",neuron.config?.enable_homeostasis),kv("energy dynamics",neuron.config?.enable_energy_dynamics),kv("traces",neuron.config?.enable_traces),kv("threshold adaptation enabled",neuron.config?.enable_threshold_adaptation)].join(""); $("rn-provenance").innerHTML = [kv("model",model),kv("family",neuron.model_provenance?.family),kv("version",neuron.model_provenance?.version),kv("canonical",neuron.model_provenance?.canonical),kv("switch count",neuron.model_switch_count),kv("last switch tick",neuron.last_model_switch_tick)].join(""); const cfg = neuron.config || {}; $("rn-config").innerHTML = Object.entries(cfg).map(([key,value]) => kv(key,value)).join(""); const runtimeTick = Number(neuron.runtime_tick ?? 0); const deltaTick = state.lastRuntimeTick === null ? 0 : runtimeTick - state.lastRuntimeTick; state.lastRuntimeTick = runtimeTick; const moving = deltaTick > 0 ? "RUNNING" : "IDLE/UNCHANGED"; $("rn-status").dataset.state = deltaTick > 0 ? "ok" : "idle"; $("rn-status").textContent = `${moving} · Tick ${runtimeTick} · Δtick ${deltaTick} · Neuron ${state.index + 1} / ${total} · ID ${neuron.neuron_id} · live_runtime`; } async function refresh() { if (state.inFlight || !$("mhrn-runtime-neuron")) return; const status = $("rn-status"); state.inFlight = true; try { if (status && state.lastRuntimeTick === null) { status.dataset.state = "ok"; status.textContent = "Live-Neuron wird gelesen …"; } const payload = await readJson(`/api/network/neurons?limit=1&offset=${state.index}`); const neuron = payload.neurons?.[0]; if (!neuron) throw new Error("Neuron an diesem Index nicht vorhanden"); render(neuron, payload.total || 0); } catch (error) { if (status) { status.dataset.state = "error"; status.textContent = `Neuron nicht verfügbar: ${error.message}`; } } finally { state.inFlight = false; } } export function initRuntimeNeuron() { ensurePanel(); const observer = new MutationObserver(syncPolling); observer.observe(document.body, { attributes: true, attributeFilter: ["data-current-area", "data-current-route"], }); document.addEventListener("click", (event) => { if (event.target.closest('[data-area-route="neuron"], [data-route-card="neuron"]')) { setTimeout(syncPolling, 0); } }); window.addEventListener("beforeunload", () => state.timer && clearInterval(state.timer), { once: true }); syncPolling(); }