2026-10-18 17:10:26 +02:00
|
|
|
package api
|
|
|
|
|
|
|
|
|
|
// Request/Response-Typen des Daemon-HTTP-Vertrags (Task-04-Brief, bindende
|
|
|
|
|
// Felder). Die CLI und spätere Konsumenten (MCP, Task 06) benutzen dieselben
|
|
|
|
|
// Typen — eine Quelle, kein Contract-Drift zwischen Daemon und Client.
|
|
|
|
|
|
|
|
|
|
// SpeakRequest ist der Body von POST /speak.
|
|
|
|
|
type SpeakRequest struct {
|
|
|
|
|
// Text ist der Ansage-Text (Pflicht).
|
|
|
|
|
Text string `json:"text"`
|
|
|
|
|
|
|
|
|
|
// Priority: low | normal | high (Default normal, wenn leer).
|
|
|
|
|
Priority string `json:"priority,omitempty"`
|
|
|
|
|
|
|
|
|
|
// Provider pinnt die Provider-Kette (--provider).
|
|
|
|
|
Provider string `json:"provider,omitempty"`
|
|
|
|
|
|
|
|
|
|
// Voice pinnt eine Voice-ID (--voice).
|
|
|
|
|
Voice string `json:"voice,omitempty"`
|
|
|
|
|
|
|
|
|
|
// Lang pinnt die Sprache de | en (leer = automatische Erkennung).
|
|
|
|
|
Lang string `json:"lang,omitempty"`
|
|
|
|
|
|
|
|
|
|
// Now lässt die Ansage vor allen wartenden springen (--now).
|
|
|
|
|
Now bool `json:"now,omitempty"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SpeakResponse ist die Antwort von POST /speak: 202 {"id":"…"} — bei
|
|
|
|
|
// aktivem Mute 202 {"id":"","muted":true} (Ansage verworfen; dokumentiertes
|
2026-10-18 17:40:46 +02:00
|
|
|
// Verhalten, kein Fehler). Seit Task 05 meldet verworfenen Spam ebenso
|
|
|
|
|
// dokumentiert: 202 {"id":"","discarded":"rate_limit"|"quiet_hours"} —
|
|
|
|
|
// plus "toast":true, wenn die Ruhezeit-Ansage durch eine Benachrichtigung
|
|
|
|
|
// ersetzt wurde (quiet_mode = "toast").
|
2026-10-18 17:10:26 +02:00
|
|
|
type SpeakResponse struct {
|
|
|
|
|
ID string `json:"id"`
|
|
|
|
|
Muted bool `json:"muted,omitempty"`
|
2026-10-18 17:40:46 +02:00
|
|
|
|
|
|
|
|
// Discarded ist der Verwurfs-Grund ("rate_limit" | "quiet_hours");
|
|
|
|
|
// leer, wenn die Ansage aufgenommen wurde.
|
|
|
|
|
Discarded string `json:"discarded,omitempty"`
|
|
|
|
|
|
|
|
|
|
// Toast meldet die Ersetzung durch eine Benachrichtigung.
|
|
|
|
|
Toast bool `json:"toast,omitempty"`
|
2026-10-18 17:10:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// CurrentItem beschreibt das laufende Item in GET /status.
|
|
|
|
|
type CurrentItem struct {
|
|
|
|
|
ID string `json:"id"`
|
|
|
|
|
Text string `json:"text"`
|
|
|
|
|
Priority string `json:"priority"`
|
|
|
|
|
Now bool `json:"now"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// StatusResponse ist die Antwort von GET /status: Queue-Länge, aktuelles
|
|
|
|
|
// Item (null im Leerlauf), Mute-State, aktiver Provider, Daemon-Version.
|
|
|
|
|
// QueueIDs ist die Ergänzung der wartenden IDs in Abarbeitungs-Reihenfolge
|
2026-10-18 17:40:46 +02:00
|
|
|
// — die CLI braucht sie für ihr --wait-Polling. Task 05 ergänzt additiv
|
2026-10-18 20:06:05 +02:00
|
|
|
// den Gesetz-State (rate_limit, quiet_hours); Task 06 additiv mcp/cors
|
|
|
|
|
// (Compat-Felder: MCP-Endpoint vorhanden, konfigurierte CORS-Origins).
|
2026-10-18 17:10:26 +02:00
|
|
|
type StatusResponse struct {
|
2026-10-18 17:40:46 +02:00
|
|
|
Version string `json:"version"`
|
|
|
|
|
Queue int `json:"queue"`
|
|
|
|
|
QueueIDs []string `json:"queue_ids,omitempty"`
|
|
|
|
|
Current *CurrentItem `json:"current"`
|
|
|
|
|
Muted bool `json:"muted"`
|
|
|
|
|
Provider string `json:"provider"`
|
|
|
|
|
RateLimit *RateLimitState `json:"rate_limit,omitempty"`
|
|
|
|
|
QuietHours *QuietHoursState `json:"quiet_hours,omitempty"`
|
2026-10-18 20:06:05 +02:00
|
|
|
|
|
|
|
|
// MCP meldet, dass der Daemon den MCP-Endpoint anbietet (immer true;
|
|
|
|
|
// Feld existiert für additive Compat-Sicht von Clients/Browsern).
|
|
|
|
|
MCP bool `json:"mcp"`
|
|
|
|
|
|
|
|
|
|
// Cors ist die konfigurierte CORS-Erlaubnisliste von POST /speak
|
|
|
|
|
// (leeres [] = Tür zu). Immer vorhanden (auch leer), nicht omitempty.
|
|
|
|
|
Cors []string `json:"cors"`
|
2026-10-18 17:40:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// RateLimitState ist der Rate-Limit-State in GET /status (Task 05).
|
|
|
|
|
type RateLimitState struct {
|
|
|
|
|
// Interval ist der konfigurierte Mindestabstand als Dauer-String
|
|
|
|
|
// ("30s"; "0s" = unbegrenzt).
|
|
|
|
|
Interval string `json:"interval"`
|
|
|
|
|
|
|
|
|
|
// AllowHighBurst meldet, ob priority=high verstoßen darf.
|
|
|
|
|
AllowHighBurst bool `json:"allow_high_burst"`
|
|
|
|
|
|
|
|
|
|
// NextSlot ist der nächste freie Ansage-Slot als RFC3339-Zeitstempel;
|
|
|
|
|
// null, wenn sofort gespielt werden dürfte (oder unbegrenzt).
|
|
|
|
|
NextSlot *string `json:"next_slot"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// QuietHoursState ist der Ruhezeit-State in GET /status (Task 05).
|
|
|
|
|
type QuietHoursState struct {
|
|
|
|
|
// Window ist das konfigurierte Fenster ("18:00-08:00"; "" = deaktiviert).
|
|
|
|
|
Window string `json:"window"`
|
|
|
|
|
|
|
|
|
|
// Active meldet, ob die lokale Zeit gerade im Fenster liegt.
|
|
|
|
|
Active bool `json:"active"`
|
|
|
|
|
|
|
|
|
|
// Mode ist der konfigurierte Ruhezeit-Modus ("discard" | "toast").
|
|
|
|
|
Mode string `json:"mode"`
|
|
|
|
|
|
|
|
|
|
// Until ist das Fenster-Ende als RFC3339-Zeitstempel, wenn aktiv;
|
|
|
|
|
// sonst null.
|
|
|
|
|
Until *string `json:"until"`
|
2026-10-18 17:10:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// PendingOrCurrent meldet, ob die Ansage mit der ID noch wartet oder
|
|
|
|
|
// gerade läuft — Grundlage des --wait-Pollings der CLI. Ist die Ansage
|
|
|
|
|
// weder wartend noch laufend, ist sie fertig (oder abgebrochen) — in
|
|
|
|
|
// beiden Fällen hat der Aufrufer nichts mehr zu warten.
|
|
|
|
|
func (s StatusResponse) PendingOrCurrent(id string) bool {
|
|
|
|
|
if s.Current != nil && s.Current.ID == id {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
for _, qid := range s.QueueIDs {
|
|
|
|
|
if qid == id {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// CancelResponse ist die Antwort von POST /cancel.
|
|
|
|
|
type CancelResponse struct {
|
|
|
|
|
Cancelled int `json:"cancelled"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MuteResponse ist die Antwort von POST /mute und POST /unmute.
|
|
|
|
|
type MuteResponse struct {
|
|
|
|
|
Muted bool `json:"muted"`
|
|
|
|
|
}
|
2026-10-24 09:49:16 +02:00
|
|
|
|
|
|
|
|
// ShutdownResponse ist die Antwort von POST /shutdown.
|
|
|
|
|
type ShutdownResponse struct {
|
|
|
|
|
OK bool `json:"ok"`
|
|
|
|
|
}
|