L3 Auftragsimport: Extraktion, Plausibilität, Dubletten, Bestätigung (Services + Tests)

- Claude-Extraktion (PDF nativ/Bild, Structured Output, Konfidenzen, Volltext), FakeProvider
- Plausibilitätsprüfung, Mapping Extraktion → Formular, Korrektur-Diff
- Services Upload/Verarbeitung/Bestätigung/Verwerfen/Neu verarbeiten, Processor import-extraction
- Stubs: storeFile (§4.3), findDuplicateCustomers (L1), createWorkOrder (L2)
- Tests test-import-rules/-flow/-live, Beispiel-PDFs + Generator

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-14 12:17:13 +02:00
co-authored by Claude Opus 5
parent bf4456718e
commit 12a764786a
22 changed files with 2592 additions and 1 deletions
+62
View File
@@ -0,0 +1,62 @@
// Lane L3 (Auftragsimport) — optional live test of the Claude extraction against a generated
// sample order confirmation. Runs ONLY when ANTHROPIC_API_KEY is set (costs tokens); otherwise
// it skips with exit 0 so the default gate stays offline.
//
// Lauf: ANTHROPIC_API_KEY=… npx tsx scripts/test-import-live.ts
import "dotenv/config";
import { getExtractionProvider } from "../src/server/ai/extraction/anthropic";
import { checkPlausibility } from "../src/lib/imports/plausibility";
import { buildPdf } from "./make-sample-pdfs";
async function main() {
if (!process.env.ANTHROPIC_API_KEY?.trim()) {
console.log("↷ übersprungen: kein ANTHROPIC_API_KEY gesetzt (Live-Extraktion gegen Claude).");
process.exit(0);
}
const provider = getExtractionProvider();
if (!provider) {
console.log("↷ übersprungen: AI_EXTRACTION_PROVIDER ist nicht anthropic.");
process.exit(0);
}
let failures = 0;
const ok = (cond: boolean, msg: string) => {
console.log(`${cond ? "✓" : "✗ FEHLER"} ${msg}`);
if (!cond) failures++;
};
const pdf = buildPdf([
[
{ text: "Kranich Haustechnik GmbH", size: 16, bold: true },
{ text: "Musterbau GmbH", gap: 40 },
{ text: "Hafenstraße 12" },
{ text: "20457 Hamburg" },
{ text: "Auftragsbestätigung", size: 14, bold: true, gap: 30 },
{ text: "Auftragsnummer: AB-2026-0815 Datum: 02.09.2026 Kundennummer: K-10042", gap: 20 },
{ text: "Bauvorhaben: Speicherhof, Am Kaiserkai 30, 20457 Hamburg" },
{ text: "Ausführung: 12.10.2026 bis 16.10.2026" },
{ text: "1 Wärmepumpe Aerotherm 12 kW WP-AT-12 1 Stk", gap: 20 },
{ text: "2 Kupferrohr 22 mm CU-22 24 m" },
],
]);
const started = Date.now();
const result = await provider.extract({ bytes: pdf, mimeType: "application/pdf", fileName: "live-sample.pdf" });
const { extraction } = checkPlausibility(result.extraction);
console.log(` Modell ${result.meta.model}, ${result.meta.inputTokens} in / ${result.meta.outputTokens} out, ${((Date.now() - started) / 1000).toFixed(1)} s`);
ok(result.text.includes("AB-2026-0815"), "(L1) full text contains the order number");
ok(extraction.companyName.value?.includes("Musterbau") === true, "(L2) customer company recognised (not the letterhead)");
ok(extraction.orderNumber.value === "AB-2026-0815" && extraction.orderNumber.confidence > 0.5, "(L3) order number with confidence");
ok(extraction.plannedStart.value === "2026-10-12", "(L4) German date normalised to ISO");
ok(extraction.siteAddress.value?.street?.includes("Kaiserkai") === true, "(L5) site address separated from customer address");
ok((extraction.positions.value ?? []).some((p) => p.quantity === 24 && p.isMaterial === true), "(L6) positions with quantity and material flag");
process.exit(failures === 0 ? 0 : 1);
}
main().catch((e) => {
console.error(e);
process.exit(1);
});