# Eigener OpenAI-kompatibler Endpunkt Die Übersicht steuert den API-Listener: Start, Stopp, Erreichbarkeit, Port, aktivierte/ausführbare Profile pro Kategorie und tatsächlich geladener Worker. Die Demo-API wurde entfernt. Einstellungen → **Endpunkt & Profile** konfiguriert Port und Veröffentlichungen. Alternativ kann jedes ausführbare Profil direkt im Profileditor am Endpunkt aktiviert werden. Neue Profile sind standardmäßig nicht veröffentlicht. Profilfreigabe lädt noch keine Gewichte. ## Zugriff und Port UI und Inferenz-API sind getrennte Listener. Standard für Inferenz: **8120**. Der vorhandene Deck-API-Token gilt für alle Inferenzrouten; Kennwort/Cookie gelten nur für die Verwaltung. Tokenrotation wirkt sofort auf neue Anfragen. Keine Token, Prompts oder Antworten werden in Zugriffslogs geschrieben. Intern erhält llama.cpp einen unabhängigen kurzlebigen Schlüssel in einer Datei mit Modus 0600. Die aktuelle Docker-Testinstallation veröffentlicht ausschließlich Host-Loopback **8120–8124**. Innerhalb dieses Bereichs ist der Port bei gestopptem Endpunkt in der GUI frei wählbar. Der Installer prüft neue Ports vor dem Ersetzen des eigenen Containers; vorhandene fremde Dienste werden nie gestoppt. Anderer Bereich: `./install.sh --update --api-ports 8130-8134 --directory `. Danach gegebenenfalls den gespeicherten API-Port in der GUI korrigieren. Bei nativem Betrieb ist jeder freie Port 1024–65535 möglich; standardmäßig wird nur an 127.0.0.1 gebunden. Kein automatischer Firewall-, WireGuard- oder DNS-Umbau. Auf dem Arbeitsplatz für API-Zugriff, zusätzlich zum bestehenden UI-Tunnel: ```sh ssh -i /Users/mike_i386/.ssh/athena_key -o BatchMode=yes \ -o ExitOnForwardFailure=yes -o ServerAliveInterval=30 \ -N -L 8120:127.0.0.1:8120 root@192.168.1.212 ``` Client-Basisadresse: `http://127.0.0.1:8120/v1`. Bei Portänderung den Tunnel entsprechend anpassen. Der Endpunkt merkt sich Start/Stopp; nach regulärem Deck-Neustart startet nur der Listener automatisch, kein Modell. ## Routen Alle Inferenzrouten benötigen `Authorization: Bearer `. | Methode | Pfad | Verhalten | |---|---|---| | GET | `/v1/models` | Nur freigegebene, ausführbare Chatprofile; kein Modellstart | | GET | `/health` | Listener-Health, ebenfalls authentifiziert | | POST | `/v1/chat/completions` | Textchat, JSON und SSE-Streaming, Sampling-Defaults aus dem Profil | | POST | `/v1/images/generations` | Qwen-Image-2.1-Rezept, n=1, `b64_json` | | POST | `/v1/images/edits` | Multipart-Formular: `model=athena-image`, `prompt`, ein bis vier `image[]`; nur wenn das aktive Profil Referenzbilder unterstützt | | POST | `/v1/audio/speech` | Qwen3-TTS CustomVoice, WAV-Ausgabe | | POST | `/v1/audio/transcriptions` | Qwen3-ASR, Multipart-WAV → JSON-Transkript | `model` ist immer der **API-Profilname**, nicht der GGUF-Dateiname. Bildaufträge verwenden die gespeicherte Auflösung, Schritte, Guidance und Seed; eine explizite `size` gilt als Formatwunsch; maßgeblich bleibt die Profilauflösung. Das Bild liegt wie beim GUI-Test im eigenen Jobverzeichnis. Kein Bildprompt wird persistiert; PNG-Metadaten sind deaktiviert. n=1; Ausgabe zunächst als Base64, keine öffentlich abrufbaren Bild-URLs. Die API ist bewusst ein Teilumfang: noch keine `/v1/responses`, Embeddings, allgemeine Bildbearbeitung für andere Modellfamilien, Video oder Musik-/Voice-Worker. Qwen Image 2.1 unterstützt Referenzbilder; TTS/STT benötigen keinen eigenen Port, sondern eigene Routen und Worker hinter demselben Listener. `/v1/images/edits` akzeptiert PNG, JPEG und WebP mit maximal 10 MiB je Bild. Die Profilfähigkeit begrenzt die Anzahl: Qwen Image 2.1 derzeit auf vier, andere Bildrezepte auf null. Die Reihenfolge der wiederholten `image[]`-Felder bleibt erhalten. Nach einem Profilwechsel gilt sofort dessen Fähigkeit; der feste Name `athena-image` bleibt bestehen. Die Bildgröße stammt wie bei `/generations` aus dem Profil. Hochgeladene Referenzen werden nur für den Auftrag im privaten Jobverzeichnis abgelegt und danach entfernt. Chat akzeptiert übliche Nachrichten, Tools, response_format, Sampling-Overrides und Streaming-Optionen; unbekannte Erweiterungsfelder werden abgelehnt. Maximal 1 MiB JSON pro Anfrage, 16 MiB gepufferte Chatantwort. Keine Chunked-Uploads oder Cross-Origin-Browserfreigabe. Internes llama.cpp-HTTP-Zeitlimit: 120 Sekunden ohne Antwortdaten, maximal 600 Sekunden für laufende SSE-Ausgabe. ## Prozesssteuerung und Speicher - Eigener nativer llama-server aus dem gewählten, geprüften CUDA-Build. Kein produktiver Container wird gestartet, gestoppt oder umkonfiguriert. - Start erfolgt nach Anfrage. Mehrere Profile dürfen dieselbe Modelldatei nutzen. Ein anderes Profil bzw. eine neue Profilrevision entlädt zunächst den eigenen Worker und startet ihn mit den gespeicherten Parametern neu. - FIFO-Warteschlange (maximal 16 wartende Aufträge, 600 Sekunden Wartezeit). Gleiches Chatprofil darf bis zur konfigurierten Slotzahl parallel antworten. Ein wartender Wechsel verhindert, dass neue Chats ihn dauerhaft überholen. Streaming hält die Modellreservierung bis zum Ende der Ausgabe. - Bildaufträge benötigen beide freien GPUs. GUI-Bildtests und API nutzen dieselbe Reservierung. GUI meldet bei belegter Reservierung einen Konflikt; API wartet. Das Sprachmodell wird vor Bildgenerierung entladen. ComfyUI wird nach jedem Bild vollständig beendet; die nächste Textanfrage lädt ihr Profil erneut. - Stoppen nimmt keine neuen Anfragen an, verwirft wartende Anfragen und lässt bereits laufende Antworten/Generierungen fertig werden, dann wird entladen. SIGTERM beendet eigene Worker. Keine Garantie für SIGKILL bei nativem Betrieb; das spätere systemd-Paket muss Prozesse über seine Cgroup vollständig aufräumen. - GPU-Auswahl über UUID-Reihenfolge; busy GPUs werden abgewiesen. Speicherprüfung vor jedem Start: reale freie GPU-/RAM-Kapazität, Cgroup-Limit, Reserven. Inaktiver, reclaimbarer Dateicache wird vom Cgroup-Verbrauch abgezogen, anonyme Belegung nicht. Ein zusätzlicher GPU-Prozess während des Betriebs beendet nur den Deck-Worker. - llama.cpp: Gesamtkontext und Slots bleiben unverändert. Shared KV (`--kv-unified`), K/V q4_0, Flash Attention on, load-mode none; derzeit diese festen Backend-Defaults. Fit ist eine **Prognose**, kein OOM-Test. Feste Tensor-Splits werden separat per `--fit-print` geprüft; falls nötig wird in höchstens zehn Schritten eine passende GPU-Layerzahl gesucht. Verhältnisse und Kontext werden dabei nicht umgeschrieben. Ohne feste Verteilung verwendet Deck die geprüften Fit-Parameter des Builds. Aktive Modellstarts bleiben an freie Ressourcen gebunden. Der alte Router kann weiterlaufen; fordert er dieselben GPUs an, beendet Deck bei erkanntem Konflikt seinen eigenen Worker. Das ersetzt keine serverweite Ressourcenkoordination. ## Interne Verwaltungs-API Nur angemeldete Oberflächensitzungen plus `X-Athena-Deck: 1`, kein API-Token: | Methode | Route | JSON | |---|---|---| | GET | `/api/v1/endpoint` | Status, Port, Zähler, Worker, Warteschlange, Profile | | POST | `/api/v1/endpoint/start` | `{}` | | POST | `/api/v1/endpoint/stop` | `{}` | | POST | `/api/v1/endpoint/config` | `{"port":8120}`; nur gestoppt | | POST | `/api/v1/endpoint/profile` | `{"id":"","enabled":true}` | Persistenz: `endpoint.json` im Deck-Zustandsverzeichnis. Aktivierte, später unvollständige/gelöschte Profile verschwinden aus `/v1/models`; bestehende Requests nutzen ihren konsistenten Profilsnapshot. Wartende Requests eines geänderten oder deaktivierten Profils werden abgewiesen. Aktive Buildänderungen gelten nach dem nächsten Entladen; Modellprofile selbst werden nicht automatisch verändert. ## Verifiziert am 28.09.2026 Isolierte HTTP-/Scheduler-Tests: Tokenrotation, Adminschutz, explizite Freigabe, Profilwechsel, Streaming-Leases, ungültige Anfragen, Warteschlange und Portkonflikte. GUI: Freigabe, Start/Stopp, Status und Portformular. Echter Test auf Athena mit separaten Testprofilen und synthetischen Eingaben: Qwen IQ4_XS Pure, Medium 160000/2 Slots/85:15 → zweites Profil 4096/1 Slot mit SSE → Qwen-Image-Rezept (512×512, 4 Schritte) → LLM. PNG geprüft; anschließend eigener Listener gestoppt und Modell entladen. Keine vorhandenen Nutzerprompts oder Anwendungslogs gelesen. Testprofile und Testzugang gehören nicht zur normalen Deck-Konfiguration. Der Test weist keine vollständige OpenAI-Kompatibilität oder Langzeitstabilität nach. ## Sprachmodelle → Testen Der interne Testchat verwendet denselben Scheduler und llama.cpp-Worker wie der API-Endpunkt, braucht aber keine Veröffentlichung des Profils und keinen API-Token im Browser. Profilauswahl, fortlaufender Textchat, Antwortlimit (bis 4096 Token), Abbrechen und explizites Entladen stehen bereit. Der Modellprozess bleibt nach einer Antwort geladen; andere Profile/Bildaufträge wechseln regulär. Entladen wird bei aktiven Anfragen abgewiesen. Abbrechen schließt nur die eigene Chatverbindung; während des eigenen Modellstarts bricht es diesen Start ab. Der Verlauf liegt nur im Browser-Arbeitsspeicher. Beim Wechsel der Ansicht oder des Profils beginnt ein neuer Verlauf. Der Server hält nur den aktuellen Testjob mit gestreamter Antwort vorübergehend im RAM; weder Prompt noch Antwort werden als Chatdatei oder Log gespeichert. Reguläre Admin-Sitzung/CSRF-Schutz gelten für GET `/api/v1/chat-tests` und POST `/api/v1/chat-tests/start`, `/cancel`, `/unload`. Start: `profile_id`, Textnachrichten `messages`, `max_tokens`. Kein Bearer-Zugriff. Diagnose zeigt Ladephase, Wartezeit/Reservierungen, reale GPU-Belegung und die Speicherprognose mit Reserve je GPU, RAM-Budget und GPU-Layerlimit. Eine Prognose ist kein Nachweis für fehlerfreien Betrieb. Bestätigte Cgroup-OOM-Kills werden als RAM-OOM gemeldet; ein GPU-OOM wird ohne eindeutigen Nachweis nicht behauptet. Ein nicht eindeutig diagnostizierter Prozessabbruch nennt Speicher, Modell/Build oder Zeitlimit als mögliche Ursachen. Bestehende Anwendungslogs werden nicht gelesen. Der interne Chat-Test liefert `job.timings` (Prefill/Generierung: Token, Millisekunden und Token/s) und `job.usage` aus der finalen llama.cpp-Streamantwort. Fehlende Messwerte bleiben leer, insbesondere bei Abbruch. Prefill zählt berechnete Token, usage die gesamte Eingabe inklusive wiederverwendetem Kontext. Modellladen und Warteschlange sind nicht Teil der Token/s. Profilfreigaben: mehrere Chatprofile, höchstens ein Bildprofil. Die Auswahl eines Bildprofils entfernt atomar alle anderen Bildfreigaben; laufende Antworten werden dadurch nicht abgebrochen. Der Haken in der Profilkarte zeigt die gespeicherte Freigabe, nicht den Ladezustand. Beim Laden alter Konfigurationen mit mehreren Bildfreigaben bleibt die erste gespeicherte Bild-ID ausgewählt. ### Sprachausgabe `POST /v1/audio/speech` verwendet ein ausdrücklich freigegebenes TTS-Profil als `model`, `input` (1–1000 Zeichen), optional `voice` (Standard Ryan), `language` (Standard German), `speed` (0,25–4; sonst Profilwert) und `response_format: "wav"`. Antwort: WAV-Datei, kein JSON. MP3 und Streaming sind noch nicht unterstützt. TTS lädt beim ersten Auftrag auf die RTX 3060 und hält den eigenen Worker für weitere Anfragen bereit. Ein geladenes Chatprofil kann parallel bestehen, sofern die RTX 3060 mindestens 7 GiB für TTS frei hat. Ein exklusiver Bild- oder Videomodus, ein inkompatibler GPU-Profilwechsel oder das Stoppen des Endpunkts entlädt TTS. Fremde GPU-Prozesse werden nicht beendet. ### Spracherkennung `POST /v1/audio/transcriptions` benötigt Bearer-Token und ein explizit freigegebenes STT-Profil. Multipart-Felder: `model` (API-Profilname), `file` (PCM16-WAV, mono, 16 kHz, maximal 120 Sekunden / 8 MiB), optional `language` (`de`, `en`, `auto`, Standard `de`), `response_format` (`json`). Antwort: `{"text":"…"}`. Andere Formate, Chunked-Uploads, Zeitstempel und Streaming werden abgelehnt. Ein STT-Auftrag zur Zeit; der CPU-Worker bleibt danach für weitere Aufnahmen geladen. Er wird bei Endpunkt-Stopp, einem neuen Build oder Fehler entladen. Keine Nutzung des alten Routers. ### Speicherverhalten von TTS und STT Unter **TTS/STT → Einrichten** lässt sich für beide Worker unabhängig **Automatisch** (Standard: beim ersten Auftrag laden und behalten), **Immer bereit** (ausgewähltes ausführbares Profil bei laufendem Endpunkt vorladen und nach Verdrängung erneut laden) oder **Nach jeder Anfrage entladen** wählen. TTS lädt in „Immer bereit“ nur im LLM-GPU-Modus und nur bei ausreichendem freiem RTX-3060-Speicher; der exklusive Videomodus behält Vorrang. STT lädt auf der CPU. Bei fehlender Laufzeit oder unzureichenden Ressourcen bleibt die Auswahl gespeichert und die Fehlermeldung erscheint in der Verwaltungs-API. Das Vorladen wird später erneut versucht und unterbricht keine fremden Dienste. Die Auswahl ändert keine Modellprofile und benötigt keine zusätzliche Runtime. Interne Verwaltungs-API (angemeldete Oberfläche): `GET /api/v1/audio-policy` liefert `settings` und `errors`; `POST /api/v1/audio-policy` erwartet `{ "kind": "tts|stt", "mode": "auto|warm|per_request", "profile_id": "Profil-ID oder null" }`. Für `warm` muss ein ausführbares Profil gewählt werden. Die Oberfläche verwendet diese API. ### Modelllisten für Clients `GET /v1/models` listet ausschließlich Chatprofile, damit Chatclients keine Bild-/Audio-Profile anbieten. Deck-Erweiterungen: `GET /v1/images/models` für Bildprofile, `GET /v1/audio/speech/models` für TTS und `GET /v1/audio/transcriptions/models` für STT. Alle Listen erfordern denselben Bearer-Token und enthalten nur freigegebene, ausführbare Profile. Die Inferenzrouten bleiben unverändert. Die Verwaltungs-API liefert weiterhin die Gesamtübersicht. Chat akzeptiert `reasoning_effort`: `none`, `minimal`, `low`, `medium`, `high`, `xhigh`, `max` werden unverändert an llama.cpp weitergereicht; `null` wird wie ein fehlendes Feld behandelt. Der installierte Build unterstützt das Feld; die konkrete Wirkung hängt vom Modell-Chattemplate ab. `none` deaktiviert dort das Reasoning. Deck erfindet keine Tokenbudgets und ignoriert gesetzte Werte nicht stillschweigend. ### Fester Bildname `athena-image` bezeichnet immer das aktuell freigegebene Bildprofil. `/v1/images/models` veröffentlicht ausschließlich diesen Alias, sofern ein ausführbares Bildprofil freigegeben ist. Direkte Namen aktivierter Bildprofile bleiben aus Kompatibilitätsgründen aufrufbar. Ohne Freigabe folgt `model_not_found`. Laufende Generierungen verwenden ihr bereits übernommenes Profil; wartende Anfragen werden bei Profiländerungen abgelehnt und können erneut gesendet werden. Die Bildgröße wird aus dem Profil übernommen. `size` (z. B. `1536x1024` oder `auto`) ist ein Wunsch und verändert weder Profil noch Speicherbedarf. Die JSON-Antwort enthält zusätzlich `athena_deck.size`, `requested_size` und `size_policy: profile`. Es erfolgt keine automatische Skalierung oder Änderung des Seitenverhältnisses. In Hermes einmalig `image_gen.openai.model: athena-image` setzen. ### Optionale Bild-Prompt-Aufbereitung Unter **Bildgenerierung → Profile → Prompt-Aufwerter** kann jedes Bildprofil Text-zu-Bild und Bildbearbeitung mit Referenzbildern getrennt ein- oder ausschalten. Aktuell sind nur die offiziellen `Qwen/Qwen-Image-2.1-PE-T2I` und `Qwen/Qwen-Image-2.1-PE-I2I` als ausführbare Rezepte hinterlegt. Die Modellkarten und die Qwen Research License sind im Dialog verlinkt; beide Downloads sind jeweils etwa 18,8 GB groß. Eine Zuordnung zu anderen Bildfamilien ist möglich, ihre Bildqualität wird dabei nicht zugesichert. Uninstallierte Aufwerter erscheinen als Profilblocker. Deck lädt den Aufwerter bei Bedarf vor dem Bildworker, führt ihn mit 5080/3060 und bei Bedarf CPU-Auslagerung aus und beendet den Prozess vor dem Start von ComfyUI. Eine CPU-only-Wahl ist möglich, aber sehr langsam. Die generierte `wh_ratio` bleibt ein Vorschlag; die gespeicherte Bildauflösung wird nicht automatisch geändert. Ein Fehler der Aufbereitung beendet den Auftrag sichtbar, statt still den Originalprompt zu verwenden. Der Bildtest zeigt über **Prompt-Aufbereitung ansehen** Original und Vorschlag; „Übernehmen“ oder „Original behalten“ überspringt die erneute Aufbereitung bei genau diesem Testauftrag. API-Bildaufträge verwenden die Profilwahl automatisch. Verwaltungs-API: `GET /api/v1/prompt-enhancers` (Installation und Vorschau), `POST /api/v1/prompt-enhancers/install` mit `{ "task": "t2i|i2i" }`, `POST /api/v1/prompt-enhancers/cancel` mit `{}`, `POST /api/v1/prompt-enhancers/preview` mit `{ "profile_id": "…", "prompt": "…" }` oder Multipart samt `image[]`; `POST /api/v1/profiles/prompt-enhancer` speichert `{ "id": "…", "revision": 1, "prompt_enhancer": { "t2i": null, "i2i": null, "device": "auto" } }` mit den offiziellen Repository-IDs statt `null` für aktive Aufgaben. Diese Routen erfordern die angemeldete Verwaltungssitzung. Der normale Bildendpunkt behält seine API-Form. ### API-Kompatibilität `api_compat.py` normalisiert Chat-Anfragen unabhängig von Client, Modellprofilen und Prozesssteuerung. Standard-Effortwerte bis `max` werden als Template-Hinweis weitergereicht. Die Erweiterung `ultra` wird auf `max` abgebildet, unabhängig davon, welcher Client sie sendet. Fehlend oder null bleibt ungesetzt; `none` wird unverändert weitergereicht. Es werden keine Tokenbudgets erfunden und keine Modellprofile verändert. Bei gesetztem Effort melden JSON- und SSE-Antworten die Header `X-Athena-Reasoning-Requested`, `X-Athena-Reasoning-Effective` und `X-Athena-Reasoning-Semantics: model-template-hint`. Der installierte llama.cpp-Build reicht positive Werte an das Chattemplate weiter; das garantiert keine unterschiedlichen Denkstufen bei Qwen. Die Wirksamkeit wird nicht aus dem Profilnamen abgeleitet. Weitere Protokollübersetzungen gehören in diesen Adapter.