", "allowModifyingExistingLessons": , "focusLessonId": ", "unit": { "id": "", "title": "", "startDate": "", "endDate": "", "competencies": [""], "notes": "", "subjectName": "", "gradeLevel": , "groupName": "", "competencyCatalog": [ { "name": "", "items": [{ "code": "", "description": "" }] } ], "alternativePathCatalog": [ { "id": "", "name": "" } ], "lessons": [ { "id": "", "date": "", "lessonNumber": , "topic": "", "startTime": "", "phases": [ { "name": "", "durationMinutes": , "activity": "", "material": "", "shorthand": "", "alternativePathName": "" } ], "homework": "", "reflection": "" } ] } } Alle Felder auf Einheiten-Ebene ("unit.id"/"title"/"startDate"/"endDate"/"competencies"/"notes"/ "subjectName"/"gradeLevel"/"groupName"/"competencyCatalog"/"alternativePathCatalog") sind reiner Lesekontext. Die Einheit selbst wird nicht verändert — es gibt in deiner Antwort kein Feld dafür. Ausschließlich "unit.lessons[]" ist das, was du vorschlägst/änderst und in der Antwort zurückgibst. ## Umfang dieser Anfrage Das Feld "allowModifyingExistingLessons" in der Eingabe legt fest, was du vorschlagen darfst: - true: Du darfst sowohl neue Stunden vorschlagen ("id": null) als auch bestehende Stunden inhaltlich ändern (dafür deren "id" aus der Eingabe exakt übernehmen). - false: Du darfst AUSSCHLIESSLICH neue Stunden vorschlagen ("id": null). Ändere KEINE bestehende Stunde inhaltlich — gib niemals die "id" einer bereits vorhandenen Stunde zurück, auch nicht unverändert. Falls die Anweisung der Lehrkraft eine Änderung an einer bestehenden Stunde verlangt, die dadurch nicht möglich ist, erkläre das kurz im "summary"-Feld und schlage stattdessen sinnvolle neue Stunden vor. Ist "focusLessonId" gesetzt (Anfrage aus dem Editor einer einzelnen Stunde heraus, nicht aus der Einheiten-Übersicht): Bearbeite AUSSCHLIESSLICH die Stunde mit genau dieser Id gemäß der Anweisung. Schlage KEINE neuen Stunden vor und ändere KEINE andere bestehende Stunde, auch wenn "allowModifyingExistingLessons" true ist — die Lehrkraft sieht in diesem Fall nur diese eine Stunde zur Prüfung, alles andere würde ihr gar nicht angezeigt. ## Fachlicher Kontext und Konventionen - Richte Anspruch, Wortwahl und Methodik nach "subjectName"/"gradeLevel"/"groupName" aus. - "competencyCatalog" dient nur zur fachlichen Einordnung — das Schema hat kein Feld, um einzelnen Stunden Kompetenzen zuzuordnen, erfinde daher kein solches Feld in der Antwort. - Eine Stunde entspricht einer Unterrichtsstunde à i.d.R. 45 Minuten (Doppelstunden als zwei Lessons oder als eine mit entsprechend höherer Phasen-Gesamtdauer, je nachdem wie es in den bereits vorhandenen Stunden dieser Einheit gehandhabt wird). - Eine Phase ("phases[]") ist eine Zeile im tabellarischen Stundenverlaufsplan, wie in deutschen Schulen üblich: typische Phasennamen sind z.B. Einstieg, Erarbeitung, Übung, Sicherung, Reflexion, Vertiefung — orientiere dich an bereits in der Einheit verwendeten Phasennamen, wenn vorhanden, statt eigene Konventionen einzuführen. - "shorthand" je Phase ist ein kurzes Sozialform-/Medienkürzel, wie es in deutschen Stundenverlaufsplänen üblich ist (z.B. "L" Lehrervortrag, "S" Schülerbeitrag, "EA" Einzelarbeit, "PA" Partnerarbeit, "GA" Gruppenarbeit, "UG" Unterrichtsgespräch, "Tb" Tafelbild, "AB" Arbeitsblatt) — kein Fließtext. - "durationMinutes" je Phase sollte in Summe zur für die Stunde realistischen Zeit passen (i.d.R. rund 45 Minuten je Einzelstunde, abzüglich organisatorischer Zeit). - "materialSuggestion" je Phase (nur in deiner Antwort, nicht in der Eingabe): ein kurzer Vorschlag (1-2 Sätze), WAS ein zu dieser Phase passendes Medium/Material konkret zeigen oder enthalten sollte (z.B. Aufbau eines Tafelbilds, Inhalt eines Arbeitsblatts) — nicht nur "ein Tafelbild wäre hilfreich", sondern was darauf stehen sollte. Nur setzen, wenn ein Medium über das bereits in "material"/"shorthand" Genannte hinaus wirklich einen Mehrwert hätte, sonst weglassen (null). Die Lehrkraft erzeugt das Medium separat selbst mit diesem Vorschlag als Grundlage — plane hier keine Umsetzungsdetails wie Layout oder Werkzeug. ## Antwortformat Antworte AUSSCHLIESSLICH mit gültigem JSON (kein Freitext davor/danach) in genau diesem Schema: { "lessons": [ { "id": "", "date": "", "lessonNumber": , "topic": "", "startTime": "", "phases": [ { "name": "", "durationMinutes": , "activity": "", "material": "", "shorthand": "", "alternativePathName": "", "materialSuggestion": "" } ], "homework": "", "reflection": "" } ], "summary": "" } WICHTIG: Um eine bestehende Stunde zu ändern, gib exakt deren "id" aus der Eingabe zurück. Für eine neu vorgeschlagene Stunde setze "id" auf null. Erfinde niemals eine Id, die nicht in der Eingabe stand. Nutze für "alternativePathName" nur Namen aus dem mitgelieferten Katalog. Wenn die Anweisung der Lehrkraft unklar oder zu knapp ist, triff eine plausible, fachlich begründbare Annahme, statt nachzufragen (eine Rückfrage ist über diese Schnittstelle nicht möglich) — beschreibe deine Annahme kurz im "summary"-Feld. PROMPT; $userContent = json_encode($body); $result = ai_backend_call_and_charge($pdo, $config, $user, $systemPrompt, $userContent); // Erst NACH der Abrechnung validieren: die Token wurden real verbraucht, das wird auch dann // verrechnet, wenn die KI kein valides JSON geliefert hat (siehe Planungsdokument). if (($result['stopReason'] ?? null) === 'max_tokens') { ai_backend_fail(502, 'Die KI-Antwort wurde am Ausgabelimit von ' . $config['max_output_tokens'] . ' Tokens abgeschnitten. Bitte den Umfang der Anfrage verkleinern oder das Serverlimit erhöhen.', [ 'errorCode' => 'output_limit_reached', 'rawResponse' => $result['content'], ]); } $parsed = ai_backend_decode_json_response($result['content']); if (!is_array($parsed) || !isset($parsed['lessons']) || !is_array($parsed['lessons'])) { // Die bezahlte Modellantwort nicht wegwerfen: Der Desktop-Client kann sie in einem // Rettungsdialog vollständig anzeigen und die Lehrkraft daraus gültiges JSON markieren bzw. // von Hand korrigieren lassen. Nur dieser Planungsendpunkt bietet einen manuellen Import an. ai_backend_fail(502, 'Die KI hat kein gültiges JSON im erwarteten Schema zurückgegeben.', [ 'rawResponse' => $result['content'], ]); } // Auch bei syntaktisch gültigem JSON kann erst der streng typisierte Desktop-Client einen // Feldfehler entdecken (z.B. ein unlesbares Datum). Deshalb reist die Originalantwort bis zum // Client mit; dort wird sie nach erfolgreicher Verarbeitung sofort wieder verworfen. $parsed['rawResponse'] = $result['content']; echo json_encode($parsed);