This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
<?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['document']['pages']) || !is_array($body['candidates'] ?? null)) {
|
||||
ai_backend_fail(400, 'Dokument oder Kandidaten fehlen.');
|
||||
}
|
||||
if (count($body['candidates']) > 500) {
|
||||
ai_backend_fail(413, 'Zu viele Textkandidaten in einer Anfrage.');
|
||||
}
|
||||
|
||||
$systemPrompt = <<<'PROMPT'
|
||||
Du klassifizierst Textblöcke aus deutschen Schul- und Verwaltungsdokumenten für einen
|
||||
Vorlageneditor. Die Geometrie wurde deterministisch aus einem PDF extrahiert und darf von dir
|
||||
niemals geändert oder ergänzt werden. Du erhältst Seiten, Textblöcke und eine Liste von Kandidaten.
|
||||
|
||||
Für jeden Kandidaten:
|
||||
- vergib einen kurzen stabilen deutschen Placeholder-Namen nur aus Buchstaben und Ziffern,
|
||||
- wähle type ausschließlich aus text, multiline, date, number,
|
||||
- wähle confidence ausschließlich aus high, medium, low,
|
||||
- darfst du benachbarte, logisch zusammengehörige Zeilen gruppieren. Dann enthält blockIds alle
|
||||
Original-IDs der Gruppe. Jede übernommene ID muss exakt aus der Eingabe stammen.
|
||||
- typische Namen sind Anrede, Empfaenger, Adresse, PlzOrt, Datum, Betreff, Aktenzeichen, Brieftext.
|
||||
|
||||
Antworte AUSSCHLIESSLICH mit gültigem JSON in diesem Schema:
|
||||
{
|
||||
"classifications": [
|
||||
{
|
||||
"id": "<id eines Kandidaten>",
|
||||
"blockIds": ["<unveränderte Original-ID>"],
|
||||
"name": "<PlaceholderName>",
|
||||
"type": "text|multiline|date|number",
|
||||
"confidence": "high|medium|low"
|
||||
}
|
||||
]
|
||||
}
|
||||
PROMPT;
|
||||
|
||||
$result = ai_backend_call_and_charge($pdo, $config, $user, $systemPrompt,
|
||||
json_encode($body, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
|
||||
$parsed = json_decode($result['content'], true);
|
||||
if (!is_array($parsed) || !is_array($parsed['classifications'] ?? null)) {
|
||||
ai_backend_fail(502, 'Die KI hat kein gültiges Klassifikations-JSON geliefert.');
|
||||
}
|
||||
|
||||
$knownIds = [];
|
||||
foreach ($body['document']['pages'] as $page) {
|
||||
foreach (($page['textBlocks'] ?? []) as $block) {
|
||||
if (isset($block['id'])) $knownIds[(string) $block['id']] = true;
|
||||
}
|
||||
}
|
||||
$candidateIds = array_fill_keys(array_map(fn($x) => (string) ($x['id'] ?? ''), $body['candidates']), true);
|
||||
$allowedTypes = ['text', 'multiline', 'date', 'number'];
|
||||
$allowedConfidence = ['high', 'medium', 'low'];
|
||||
foreach ($parsed['classifications'] as $classification) {
|
||||
if (!isset($candidateIds[(string) ($classification['id'] ?? '')])
|
||||
|| !in_array($classification['type'] ?? '', $allowedTypes, true)
|
||||
|| !in_array($classification['confidence'] ?? '', $allowedConfidence, true)
|
||||
|| !preg_match('/^[\pL\pN]+$/u', (string) ($classification['name'] ?? ''))
|
||||
|| !is_array($classification['blockIds'] ?? null)) {
|
||||
ai_backend_fail(502, 'Die KI-Klassifikation enthält ungültige Werte.');
|
||||
}
|
||||
foreach ($classification['blockIds'] as $blockId) {
|
||||
if (!isset($knownIds[(string) $blockId])) {
|
||||
ai_backend_fail(502, 'Die KI-Klassifikation referenziert einen unbekannten Textblock.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode(['classifications' => $parsed['classifications']], JSON_UNESCAPED_UNICODE);
|
||||
|
||||
Reference in New Issue
Block a user