Files
LehrerApp/ai-backend/untis-status.php
T
admin 1291b24478
CI / build-and-test (push) Canceled after 0s
Untis-Fehlzeiten und Dashboard-Hinweise verfeinern
2026-09-25 12:09:32 +02:00

82 lines
3.7 KiB
PHP

<?php
declare(strict_types=1);
require_once __DIR__ . '/db.php';
header('Content-Type: application/json');
$config = require __DIR__ . '/config.php';
$pdo = ai_backend_db($config);
$user = ai_backend_authenticate($pdo);
if ((float) $user['balance_usd'] <= 0) {
ai_backend_fail(402, 'Kein Guthaben mehr vorhanden.');
}
$body = json_decode(file_get_contents('php://input'), true);
if (!is_array($body) || !isset($body['rows']) || !is_array($body['rows']) || count($body['rows']) === 0) {
ai_backend_fail(400, 'Ungültige Anfrage.');
}
// Datensparsamkeit (Nutzer-Feedback zum Untis-Hub): dieser Endpunkt bekommt bewusst NIE Namen,
// Klassen oder Datumsangaben - nur eine je Zeile rein technische, für die KI bedeutungslose "id"
// (für die Rückzuordnung im Desktop-Client) sowie die für die Statuseinschätzung tatsächlich
// relevanten Felder aus dem WebUntis-Fehlzeitendatensatz. Mehrere Zeilen eines Abgleichslaufs
// werden in einer Anfrage gebündelt statt je Zeile eine eigene Anfrage zu stellen (Kosten/Latenz).
$systemPrompt = <<<PROMPT
Du hilfst einer Lehrkraft beim Abgleich von WebUntis-Fehlzeiten mit dem internen Anwesenheitsstatus
ihrer Schulverwaltungs-App. Du bekommst eine Liste anonymisierter Fehlzeiten-Zeilen (KEINE Namen,
KEINE Klassen, KEINE Daten) und sollst je Zeile den passendsten internen Status vorschlagen.
## Eingabeschema
{
"rows": [
{
"id": "<rein technische Kennung ohne inhaltliche Bedeutung, exakt so zurückzugeben>",
"reasonText": "<Freitext-Grund aus WebUntis, kann leer sein>",
"absentMinutes": <Zahl, gemeldete Fehlminuten der Unterrichtsstunde>,
"handledOn": <true, wenn der Eintrag laut WebUntis bereits vom Klassenlehrer bearbeitet wurde>,
"externKeyInParentheses": <true/false/null - schulinterne Konvention: Klammerung der
Entschuldigungsnummer bedeutet unentschuldigt, ohne Klammern entschuldigt; null, wenn keine
Nummer hinterlegt ist>,
"currentGuess": "<bereits regelbasiert ermittelter Status, siehe Schlüsselliste unten>"
}
]
}
## Möglicher Zielstatus (exakt einer dieser Schlüssel je Zeile)
- "Present": eigentlich anwesend (z.B. wenn der Freitext klar nahelegt, dass die Fehlzeit ein Irrtum war)
- "Late": weniger als 10 Minuten verspätet
- "SignificantlyLate": mindestens 10, aber weniger als 45 Minuten verspätet
- "LeftDuringClass": während des Unterrichts nach Hause entlassen/gegangen
- "ExcusePending": krank gemeldet, Entschuldigung noch offen/unbearbeitet
- "Excused": krank, entschuldigt
- "Unexcused": unentschuldigt
## Aufgabe
"currentGuess" kommt aus einer festen Regel über die strukturierten Felder und ist im Zweifel schon
korrekt - weiche davon nur ab, wenn "reasonText" eindeutig eine andere Einordnung nahelegt (z.B. ein
Text, der klar auf eine Klassenfahrt, einen Arzttermin mit bereits vorliegendem Attest, oder einen
erkennbaren Fehleintrag hindeutet). Bei Unsicherheit "currentGuess" unverändert übernehmen, nicht raten.
## Antwortformat
Antworte AUSSCHLIESSLICH mit gültigem JSON (kein Freitext davor/danach), mit GENAU einem Eintrag je
Eingabe-"id" (dieselbe Anzahl, dieselben "id"-Werte unverändert, keine erfundenen oder ausgelassenen
ids):
{ "suggestions": [ { "id": "<unverändert aus der Eingabe>", "status": "<einer der Schlüssel oben>" } ] }
PROMPT;
$userContent = json_encode($body);
$result = ai_backend_call_and_charge($pdo, $config, $user, $systemPrompt, $userContent);
$parsed = ai_backend_decode_json_response($result['content']);
if (!is_array($parsed) || !isset($parsed['suggestions']) || !is_array($parsed['suggestions'])) {
ai_backend_fail(502, 'Die KI hat kein gültiges JSON im erwarteten Schema zurückgegeben.');
}
echo json_encode($parsed);