Files
dogfather-universe/workspace/assets/js/ki.js
T
DogFatherGitandClaude Opus 5 461d41943a Keine Maschinensprache mehr auf dem Bildschirm
Filipe: "keine kryptischen oder technischen fehlermeldungen, sondern
klare aussagen darueber, was passiert ist und wie man das problem
loesen kann."

DAS PROBLEM, NACHGEMESSEN.

Der Server antwortet im Fehlerfall mit { fehler: "..." }. Darin stehen
ZWEI verschiedene Dinge, und von aussen sehen sie gleich aus:
Maschinenkennungen (nicht_verfuegbar, nicht_gefunden, ungueltig -- 43
verschiedene) und fertige deutsche Saetze.

An 84 Stellen stand `textContent = d.fehler` -- ungefiltert. Wer beim
Hochladen einer Datei Pech hatte, las woertlich "nicht_verfuegbar" auf
dem Bildschirm und wusste nicht einmal, ob er selbst schuld war.

Gezaehlt: 474 Antworten mit "nicht_verfuegbar", 392 mit
"nicht_gefunden", 125 mit "ungueltig".

DREI AUSGAENGE, NICHT ZWEI.

`sagWas()` in workspace/assets/js/meldung.js:
  bekannte Kennung   -> ihr Satz
  unbekannte Kennung -> der Ersatzsatz der Stelle, NIE die Kennung
                        (sie geht in die Konsole, wo sie jemandem
                        auffaellt, der sie beheben kann)
  fertiger Satz      -> unveraendert durch

Erkannt wird eine Kennung daran, dass sie nur aus Kleinbuchstaben,
Ziffern und Unterstrichen besteht. Ein deutscher Satz hat immer
Leerzeichen; eine Kennung nie. Die Unterscheidung ist entschieden,
nicht geraten.

UND WARUM DIE TABELLE NICHT ALTERN KANN.

Eine von Hand gepflegte Liste ist hier schon zweimal teuer geworden
(die abgeschriebene Spaltenliste, die feste Umbruchschwelle). Deshalb
rechnet pruef-meldungen.mjs die Kennungen AUS DEM SERVER aus statt sie
zu kennen -- eine neue ohne Satz macht sie rot. Man kann es nicht mehr
vergessen.

Sie prueft drei Dinge und beweist zu jedem, dass sie auch "nicht in
Ordnung" sagen kann:
  1. vollstaendig -- jede Kennung hat einen Satz
  2. angeschlossen -- keine Rohanzeige, und jede Seite, deren Skript
     sagWas benutzt, laedt auch meldung.js
  3. lesbar -- kein Satz enthaelt Kennung, Zahl oder englisches Wort

GEFUNDEN HAT SIE SOFORT EINEN ECHTEN FEHLER: leistung.html laedt seine
Skripte ohne `defer` und fiel damit durch meinen Einbau. Dort waere
sagWas nicht definiert gewesen -- aus einer Fehlermeldung waere ein
Absturz geworden, also schlimmer als vorher.

NEBENBEFUND, DER MICH FAST EINE FALSCHE MELDUNG GEKOSTET HAETTE:
"alter_offen" heisst NICHT "etwas Aelteres ist offen", sondern
"Altersbestaetigung steht noch aus" (workspace.js:4864). Geraten
haette ich es falsch uebersetzt.

GEMESSEN: pruef-meldungen 8/0, alle 46 Skripte syntaktisch in Ordnung.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-19 14:46:13 +02:00

89 lines
3.2 KiB
JavaScript

/* ===================================================================
Gemeinsamer Zugang zur lokalen KI.
Liegt in einer eigenen Datei, weil drei Seiten sie benutzen (Calls,
Start-Check, Report) und die Absicherung sonst dreimal dastuende --
und beim naechsten Mal in zwei davon.
ZWEI REGELN:
1. IST DIE KI AUS, GIBT ES DEN KNOPF NICHT. Ein Knopf, der immer eine
Fehlermeldung bringt, ist schlimmer als gar kein Knopf. Deshalb
fragt jede Seite beim Laden einmal nach und baut ihn nur dann.
2. DIE KI SCHLAEGT VOR, DER MENSCH ENTSCHEIDET. Kein Aufruf hier
speichert etwas. Was uebernommen wird, traegt der Mensch an
derselben Stelle ein wie ohne KI.
=================================================================== */
window.KI = (() => {
'use strict';
let bekannt = null; // null = noch nicht gefragt
/* Einmal pro Seitenaufruf fragen, danach gemerkt. */
async function verfuegbar() {
if (bekannt !== null) return bekannt;
try {
const a = await fetch('/workspace/api/ki/status', { credentials: 'same-origin' });
bekannt = a.ok ? (await a.json()).da === true : false;
} catch { bekannt = false; }
return bekannt;
}
async function frage(pfad, koerper) {
const a = await fetch('/workspace/api/ki/' + pfad, {
method: 'POST',
credentials: 'same-origin',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(koerper),
});
if (a.status === 401) { location.assign('/workspace/'); throw new Error('abgemeldet'); }
const d = await a.json().catch(() => ({}));
if (!a.ok) throw new Error(sagWas(d.fehler, 'Die KI konnte nicht antworten.'));
return d;
}
/* Baut einen Knopf, der waehrend des Denkens sagt, dass er denkt --
zwoelf Sekunden ohne Rueckmeldung fuehlen sich an wie ein Fehler. */
function knopf(beschriftung, tuWas) {
const b = document.createElement('button');
b.type = 'button';
b.className = 'ki-knopf';
const funke = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
funke.setAttribute('viewBox', '0 0 24 24');
funke.setAttribute('class', 'ki-knopf__funke');
funke.setAttribute('aria-hidden', 'true');
funke.innerHTML = '<path d="M12 3.2 13.7 9l5.8 1.7-5.8 1.7L12 18.2l-1.7-5.8L4.5 10.7 10.3 9z"/>'
+ '<path d="M18.4 3.4l.6 2 2 .6-2 .6-.6 2-.6-2-2-.6 2-.6z"/>';
const text = document.createElement('span');
text.textContent = beschriftung;
b.append(funke, text);
b.addEventListener('click', async () => {
if (b.disabled) return;
b.disabled = true;
b.dataset.denkt = 'ja';
const vorher = text.textContent;
text.textContent = 'Die KI denkt …';
try {
await tuWas();
} catch (fehler) {
/* Die Meldung gehoert dorthin, wo der Knopf steht -- nicht in
ein Fenster, das den Rest verdeckt. */
const hinweis = document.createElement('span');
hinweis.className = 'ki-fehler';
hinweis.textContent = fehler.message;
b.after(hinweis);
setTimeout(() => hinweis.remove(), 7000);
} finally {
delete b.dataset.denkt;
text.textContent = vorher;
b.disabled = false;
}
});
return b;
}
return { verfuegbar, frage, knopf };
})();