feat(ki): Einstellungen -> KI mit OpenAI-Schluessel und Modellwahl

Neuer Admin-Reiter "KI": zeigt die letzten vier Zeichen des hinterlegten
OpenAI-Schluessels samt Quelle, nimmt einen neuen an (vorher gegen
/v1/models geprueft) und laesst je Einsatzzweck das Modell per Dropdown
waehlen - Scanner-Bewertung, Abgleich "bereits beworben", erweiterte Suche.
Die Auswahl kommt live von OpenAI, Vorgaben sind die bisher fest
verdrahteten Modelle. Reasoning-Modelle bekommen reasoning_effort statt
temperature, damit ein Wechsel keinen 400er ausloest.

Schluesselfeld aus dem Scanner-Reiter entfernt; Doku in docs/14-ki.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Sascha Wolf
2026-09-23 10:31:55 +02:00
co-authored by Claude Opus 5.5
parent 0d41d46a3c
commit e35c7518db
26 changed files with 930 additions and 144 deletions
+4 -3
View File
@@ -99,11 +99,11 @@ werden:
Die erweiterte Suche benutzt **denselben OpenAI-Schlüssel wie der Scanner** –
`openai_api_key` in der Scanner-Tabelle `settings`, gepflegt unter
*Einstellungen → Scanner*, ersatzweise `OPENAI_API_KEY` aus der Umgebung. Ein
*Einstellungen → KI* (siehe [14 KI](14-ki.md)), ersatzweise `OPENAI_API_KEY` aus der Umgebung. Ein
zweiter Schlüssel an zweiter Stelle wäre eine Quelle für den Fall „die eine
Funktion geht, die andere nicht, und keiner weiß warum".
Modell: `gpt-4o-mini`, wie im Scanner. Fehlt der Schlüssel, antwortet der
Modell: einstellbar unter *Einstellungen → KI*, Vorgabe `gpt-4o-mini`. Fehlt der Schlüssel, antwortet der
Endpunkt mit `503` und dem Hinweis auf die Einstellungen; die Volltextsuche
bleibt davon unberührt.
@@ -116,7 +116,8 @@ Scanner behält sein SDK, dort hängt mehr daran.
| Datei | Aufgabe |
| --- | --- |
| `server/src/routes/search.js` | beide Endpunkte |
| `server/src/ai.js` | OpenAI-Aufruf, Schlüssel des Scanners |
| `server/src/ai.js` | OpenAI-Aufruf, Schlüssel, Modellwahl |
| `server/src/routes/ai.js` | Einstellungen → KI (siehe [14 KI](14-ki.md)) |
| `server/src/routes/iconCrm.js` | `fetchIconContacts()` samt Zwischenspeicher |
| `src/components/GlobalSearch.tsx` | das Feld, beide Modi, die Trefferliste |
| `src/components/Header.tsx` | bindet es mittig in die Kopfleiste ein |