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
+24
View File
@@ -231,6 +231,30 @@ Eigenheiten, die man kennen muss:
Funktionen `mailConfigured()` und `ssoConfigured()` - die Prüfung muss in die
Datenbank sehen.
### `server/src/ai.js`
OpenAI-Schlüssel, Modellwahl je Einsatzzweck und der Aufruf der erweiterten
Suche. Gepflegt unter *Einstellungen → KI*, Details in [14 KI](14-ki.md).
| Export | Zweck |
| --- | --- |
| `aiKey()` / `aiConfigured()` | gültiger Schlüssel, Datenbank vor `.env` |
| `keyStatus()` | Quelle und letzte vier Zeichen - nie der ganze Schlüssel |
| `verifyKey()` / `saveKey()` / `clearKey()` | Probe bei OpenAI, schreiben, zurücknehmen |
| `AI_PURPOSES`, `modelFor(zweck)` | Einsatzzwecke mit Vorgabe; eingestelltes Modell oder Vorgabe |
| `modelSettings()` / `saveModels()` / `availableModels()` | Modellwahl lesen, schreiben, Auswahlliste von OpenAI |
| `isReasoningModel()` | `reasoning_effort` statt `temperature`, in `test/ai.test.mjs` geprüft |
| `askModelJson()` | ein Chat-Completions-Aufruf mit JSON-Antwort |
Eigenheiten, die man kennen muss:
* Der Schlüssel liegt in der **Scanner**-Datenbank (`settings.openai_api_key`),
die Modellwahl in der **CRM**-Datenbank (`crm_settings.ai_model_*`). Der
Schlüssel stand dort schon immer; die Modellwahl ist CRM-weit.
* Scanner-Dienste (`matchingEngine.js`, `appliedCheck.js`) holen Schlüssel und
Modell ebenfalls hier - keiner liest `openai_api_key` mehr selbst.
* Kein Zwischenspeicher: jede Änderung wirkt beim nächsten Aufruf.
### `server/src/sso/`
Anmeldung über Microsoft Entra, fachlich in