Some checks failed
Test Suite / playwright-tests (push) Waiting to run
Deploy Development / deploy (push) Successful in 43s
Test Suite / pytest-backend (push) Failing after 1s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 13s
Test Suite / k6 /health Baseline (push) Has been cancelled
- Updated the exercise form to include a tabbed navigation structure, improving user experience with sections for Stammdaten, Anleitung, Einordnung, Varianten, and Medien & Mehr. - Introduced the concept of **Freigabelevel** (visibility level) in the UI, replacing previous terminology for clarity and consistency across components. - Implemented new AI endpoints for exercise suggestions and regeneration, allowing for dynamic content generation without direct database writes. - Removed the legacy `is_primary` flag from exercise skills in the UI, ensuring that intensity levels (`niedrig`, `mittel`, `hoch`) are the primary focus for skill management. - Enhanced the variant management process with improved saving mechanisms and UI updates to reflect changes more intuitively.
374 lines
13 KiB
Markdown
374 lines
13 KiB
Markdown
# KI-Funktionen Specification – Exercises
|
||
|
||
**Version:** 1.1
|
||
**Datum:** 2026-04-24
|
||
**Status:** DRAFT
|
||
**Autor:** Claude Code
|
||
**Änderungen v1.1:** Prompts sind nicht hardcoded – sie werden aus der DB geladen (AI_PROMPT_SYSTEM_SPEC.md)
|
||
**Verwandte Specs:** AI_PROMPT_SYSTEM_SPEC.md (Prompt-DB + Platzhalter), SKILLS_MATRIX_SPEC.md (Fähigkeitsmatrix)
|
||
|
||
**Übergeordnete Produkt-Vision** (breiter Scope: Zielausbau, bereichsweise vs. Gesamtüberarbeitung, Varianten, Planungs-/Nachbereitungskontext, Admin-Masse):
|
||
`functional/AI_EXERCISE_ASSISTANT_VISION.md`
|
||
|
||
---
|
||
|
||
## 1. Übersicht
|
||
|
||
KI-gestützte Assistenzfunktionen beim Anlegen und Bearbeiten von Übungen (Mindestpaket dieser Spec):
|
||
|
||
**Hinweis:** Die beiden folgenden Zeilen entsprechen **P0** der Phasierung in **`AI_EXERCISE_ASSISTANT_VISION.md`**; spätere Funkteile sind dort beschrieben.
|
||
|
||
| Funktion | Ziel |
|
||
|---------|------|
|
||
| **KI-Zusammenfassung** | Generiert `summary` aus `goal` + `execution` (für Listen + Trainingspläne) |
|
||
| **KI-Skill-Empfehlung** | Schlägt passende Fähigkeiten + Stufen vor (reduziert manuelle Zuordungsarbeit) |
|
||
|
||
**Abhängigkeit:** OpenRouter API (`OPENROUTER_API_KEY` in `.env`).
|
||
Ist der Key nicht gesetzt, sind alle KI-Funktionen deaktiviert – Formular funktioniert ohne KI normal.
|
||
|
||
---
|
||
|
||
## 2. UX-Prinzip: Manual First, Auto als Fallback
|
||
|
||
```
|
||
Trainer gibt goal + execution ein
|
||
│
|
||
├─► [KI-Vorschlag]-Button sichtbar
|
||
│ │
|
||
│ ▼ (Klick)
|
||
│ KI generiert sofort Vorschlag
|
||
│ → Trainer sieht Vorschlag inline
|
||
│ → Kann akzeptieren / bearbeiten / ablehnen
|
||
│
|
||
└─► Kein Klick bis zum Speichern?
|
||
│
|
||
▼ (automatisch beim POST/PUT)
|
||
KI läuft im Hintergrund
|
||
→ summary + skill_suggestions werden gesetzt
|
||
→ Trainer kann danach noch bearbeiten
|
||
```
|
||
|
||
**Regel:** Manuell generierte Werte (wo Trainer aktiv bestätigt hat) werden
|
||
beim Auto-Fallback NICHT überschrieben. Auto-generierte Werte werden als
|
||
`ai_generated: true` markiert und können jederzeit neu generiert oder überschrieben werden.
|
||
|
||
---
|
||
|
||
## 3. KI-Zusammenfassung (`summary`)
|
||
|
||
### 3.1 Was wird generiert
|
||
|
||
Aus `title` + `goal` + `execution` generiert die KI eine **kurze Zusammenfassung**
|
||
(2-4 Sätze, max. 200 Zeichen) für:
|
||
- Übungslisten (Karten-Ansicht)
|
||
- Trainingsplan-Darstellung (kompakte Anzeige)
|
||
- Export-Berichte
|
||
|
||
### 3.2 Prompt-Logik (Backend)
|
||
|
||
**Prompt ist NICHT hardcoded** – er wird aus der `ai_prompts` Tabelle geladen
|
||
(Slug: `exercise_summary`). Admins können das Template anpassen.
|
||
|
||
```python
|
||
# Aufruf via zentralem AI-Service (siehe AI_PROMPT_SYSTEM_SPEC.md)
|
||
result = await ai_service.run_ai_prompt(
|
||
slug="exercise_summary",
|
||
context_data={"exercise": exercise_data},
|
||
db=db,
|
||
openrouter_key=settings.openrouter_api_key
|
||
)
|
||
```
|
||
|
||
**Default-Template** (in Migration 020 als `default_template` gespeichert):
|
||
Siehe `AI_PROMPT_SYSTEM_SPEC.md` §2.1 – Prompt `exercise_summary`.
|
||
|
||
### 3.3 DB-Feld
|
||
|
||
Kein neues Feld nötig – `exercises.summary` nimmt den generierten Text auf.
|
||
Zusätzliches Tracking-Feld: `summary_ai_generated BOOLEAN DEFAULT false`
|
||
|
||
---
|
||
|
||
## 4. KI-Skill-Empfehlung
|
||
|
||
### 4.1 Was wird empfohlen
|
||
|
||
Aus `title` + `goal` + `execution` + Katalog aller verfügbaren Skills empfiehlt die KI:
|
||
|
||
- **Welche Skills** relevant sind (aus dem bestehenden Skill-Katalog)
|
||
- **Erforderliche Stufe** (`required_level`) – was der Trainierende mitbringen muss
|
||
- **Ziel-Stufe** (`target_level`) – was durch regelmäßige Ausführung erreicht wird
|
||
- **Intensität** (`intensity`) – wie stark diese Fähigkeit trainiert wird
|
||
|
||
### 4.2 Prompt-Logik (Backend)
|
||
|
||
**Prompt ist NICHT hardcoded** – Slug: `exercise_skill_suggestions`.
|
||
Der `{{skills_catalog}}`-Platzhalter wird vom Backend automatisch mit der aktuellen
|
||
Skill-Liste aus der DB aufgelöst.
|
||
|
||
Admins können den Prompt anpassen (z.B. die Anweisung zur Auswahl verschärfen oder
|
||
fachliche Hinweise ergänzen). Siehe `AI_PROMPT_SYSTEM_SPEC.md`.
|
||
|
||
### 4.3 Bestätigungsflow (UX)
|
||
|
||
```
|
||
KI gibt Vorschläge
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────┐
|
||
│ KI-Vorschläge (3 Fähigkeiten) │
|
||
│ ─────────────────────────────────────── │
|
||
│ ✓ Distanzgefühl │
|
||
│ Voraussetzung: Grundlagen │
|
||
│ Ziel: Aufbau · Intensität: Hoch │
|
||
│ [✓ Übernehmen] [Stufe ändern ▼] [✕] │
|
||
│ ─────────────────────────────────────── │
|
||
│ ✓ Reaktionsschnelligkeit │
|
||
│ Voraussetzung: Einsteiger │
|
||
│ Ziel: Grundlagen · Intensität: Mittel │
|
||
│ [✓ Übernehmen] [Stufe ändern ▼] [✕] │
|
||
│ ─────────────────────────────────────── │
|
||
│ ◦ Gleichgewicht (optional) │
|
||
│ Voraussetzung: Grundlagen │
|
||
│ Ziel: Grundlagen · Intensität: Niedrig│
|
||
│ [✓ Übernehmen] [Stufe ändern ▼] [✕] │
|
||
│ ─────────────────────────────────────── │
|
||
│ [Alle übernehmen] [Verwerfen] │
|
||
└─────────────────────────────────────────┘
|
||
```
|
||
|
||
- Jeder Vorschlag kann **einzeln** übernommen, angepasst oder abgelehnt werden
|
||
- „Alle übernehmen" nimmt alle aktuell angezeigten Vorschläge
|
||
- Stufen können per Dropdown direkt angepasst werden bevor sie übernommen werden
|
||
- Abgelehnte Vorschläge werden nicht gespeichert
|
||
|
||
---
|
||
|
||
## 5. API-Endpoints
|
||
|
||
### 5.1 Endpoints Overview
|
||
|
||
| Method | Endpoint | Beschreibung |
|
||
|--------|----------|--------------|
|
||
| POST | `/exercises/ai/suggest` | Vorschläge für neue Übung (vor dem Speichern) |
|
||
| POST | `/exercises/{id}/ai/regenerate` | Neu generieren für bestehende Übung |
|
||
|
||
---
|
||
|
||
### 5.2 `POST /exercises/ai/suggest`
|
||
|
||
Liefert KI-Vorschläge auf Basis von Eingabe-Text, **bevor** die Übung gespeichert wurde.
|
||
Wird beim Klick auf „KI-Vorschlag" im Formular aufgerufen.
|
||
|
||
**Request Body:**
|
||
```json
|
||
{
|
||
"title": "Maai - Distanzübung",
|
||
"goal": "Distanzgefühl entwickeln durch Partnerübungen...",
|
||
"execution": "1. Partnerwahl\n2. Ausgangsstellung..."
|
||
}
|
||
```
|
||
|
||
**Required Fields:** mindestens `goal` ODER `execution` (je länger, desto besser)
|
||
|
||
**Response:** `200 OK`
|
||
```json
|
||
{
|
||
"summary": {
|
||
"text": "Partnerübung zur Entwicklung des Distanzgefühls. Trainiert werden räumliche Wahrnehmung und reaktives Verhalten in der Kumite-Distanz.",
|
||
"ai_generated": true,
|
||
"model": "anthropic/claude-sonnet-4"
|
||
},
|
||
"skills": [
|
||
{
|
||
"skill_id": 10,
|
||
"skill_name": "Distanzgefühl",
|
||
"skill_category": "Kumite",
|
||
"required_level": "grundlagen",
|
||
"target_level": "aufbau",
|
||
"intensity": "hoch",
|
||
"confidence": 0.92
|
||
},
|
||
{
|
||
"skill_id": 15,
|
||
"skill_name": "Reaktionsschnelligkeit",
|
||
"skill_category": "Athletik",
|
||
"required_level": "einsteiger",
|
||
"target_level": "grundlagen",
|
||
"intensity": "mittel",
|
||
"confidence": 0.74
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
**Errors:**
|
||
- `400` - Zu wenig Text (goal und execution leer)
|
||
- `503` - KI nicht verfügbar (OPENROUTER_API_KEY fehlt)
|
||
|
||
---
|
||
|
||
### 5.3 `POST /exercises/{id}/ai/regenerate`
|
||
|
||
Generiert summary und/oder skill-Empfehlungen für eine bestehende Übung neu.
|
||
Verwendet die aktuellen gespeicherten Felder als Input.
|
||
|
||
**Request Body:**
|
||
```json
|
||
{
|
||
"regenerate": ["summary", "skills"]
|
||
}
|
||
```
|
||
|
||
**Werte:** `"summary"` | `"skills"` (oder beide)
|
||
|
||
**Response:** `200 OK` (gleiche Struktur wie `/ai/suggest`)
|
||
|
||
**Hinweis:** Regenerieren überschreibt NICHT Felder, die manuell gesetzt wurden
|
||
(`summary_ai_generated = false`). Es wird nur der Vorschlag zurückgegeben,
|
||
Trainer muss aktiv übernehmen.
|
||
|
||
---
|
||
|
||
## 6. Datenbank
|
||
|
||
### 6.1 Neues Feld: `summary_ai_generated`
|
||
|
||
```sql
|
||
-- Als Teil von Migration 014 ergänzen:
|
||
ALTER TABLE exercises
|
||
ADD COLUMN IF NOT EXISTS summary_ai_generated BOOLEAN DEFAULT false;
|
||
```
|
||
|
||
**Semantik:**
|
||
- `false` (default) = Zusammenfassung manuell geschrieben oder noch leer
|
||
- `true` = Zuletzt von KI generiert (kann überschrieben werden)
|
||
|
||
Beim manuellen Überschreiben durch den Trainer: `summary_ai_generated = false` setzen.
|
||
|
||
### 6.2 Kein Feld für Skill-Empfehlungen
|
||
|
||
Skill-Vorschläge der KI werden **nicht** persistent gespeichert – sie erscheinen
|
||
nur im Formular-UI und werden erst bei expliziter Bestätigung als reguläre
|
||
`exercise_skills`-Einträge gespeichert.
|
||
|
||
---
|
||
|
||
## 7. Integration in Speicher-Flow
|
||
|
||
### 7.1 Auto-Fallback beim Speichern (POST/PUT exercises)
|
||
|
||
```python
|
||
# In backend/routers/exercises.py
|
||
async def create_exercise(data, session):
|
||
# 1. Übung normal speichern
|
||
exercise_id = db.insert_exercise(data)
|
||
|
||
# 2. Auto-KI nur wenn:
|
||
# - OPENROUTER_API_KEY gesetzt
|
||
# - summary noch leer
|
||
# - goal oder execution vorhanden
|
||
if settings.openrouter_api_key and not data.summary and (data.goal or data.execution):
|
||
# Background Task (non-blocking)
|
||
background_tasks.add_task(
|
||
auto_generate_summary,
|
||
exercise_id=exercise_id,
|
||
title=data.title,
|
||
goal=data.goal,
|
||
execution=data.execution
|
||
)
|
||
|
||
return exercise_id
|
||
```
|
||
|
||
### 7.2 Skill-Auto-Suggestion
|
||
|
||
Skill-Empfehlungen werden beim Auto-Fallback **NICHT** automatisch gespeichert
|
||
(wegen Bestätigungs-Pflicht). Sie werden nur beim manuellen Trigger angeboten.
|
||
|
||
---
|
||
|
||
## 8. Frontend-Integration
|
||
|
||
### 8.1 ExerciseFormPage – KI-Buttons
|
||
|
||
```
|
||
┌──────────────────────────────────────┐
|
||
│ Ziel der Übung * │
|
||
│ ┌────────────────────────────────┐ │
|
||
│ │ Distanzgefühl entwickeln... │ │
|
||
│ └────────────────────────────────┘ │
|
||
│ │
|
||
│ Durchführung * │
|
||
│ ┌────────────────────────────────┐ │
|
||
│ │ 1. Partnerwahl... │ │
|
||
│ └────────────────────────────────┘ │
|
||
│ ↓ │
|
||
│ Zusammenfassung (für Listen) │
|
||
│ ┌────────────────────────────────┐ │
|
||
│ │ [Leer] │ │
|
||
│ └────────────────────────────────┘ │
|
||
│ [✨ KI-Vorschlag] ← Button │
|
||
│ │
|
||
│ ─────────────────────────────────── │
|
||
│ Fähigkeiten │
|
||
│ [Keine zugeordnet] │
|
||
│ [+ Manuell hinzufügen] │
|
||
│ [✨ KI-Empfehlungen] ← Button │
|
||
└──────────────────────────────────────┘
|
||
```
|
||
|
||
### 8.2 KI-Vorschlag für Summary (Inline)
|
||
|
||
Beim Klick auf „✨ KI-Vorschlag":
|
||
```
|
||
┌──────────────────────────────────────┐
|
||
│ ✨ KI-Vorschlag │
|
||
│ ─────────────────────────────────── │
|
||
│ "Partnerübung zur Entwicklung des │
|
||
│ Distanzgefühls. Trainiert räumliche │
|
||
│ Wahrnehmung und reaktives Verhalten."│
|
||
│ ─────────────────────────────────── │
|
||
│ [✓ Übernehmen] [✕ Verwerfen] │
|
||
└──────────────────────────────────────┘
|
||
```
|
||
|
||
Nach „Übernehmen": Text landet im Summary-Feld, Button zeigt „↺ Neu generieren".
|
||
|
||
### 8.3 Anzeige KI-generierter Inhalte
|
||
|
||
Felder die KI-generiert sind, werden mit einem kleinen Badge markiert:
|
||
```
|
||
Zusammenfassung ✨ KI-generiert [bearbeiten]
|
||
```
|
||
|
||
Nach manuellem Bearbeiten verschwindet der Badge.
|
||
|
||
---
|
||
|
||
## 9. Konfiguration
|
||
|
||
```env
|
||
OPENROUTER_API_KEY=sk-or-...
|
||
OPENROUTER_MODEL=anthropic/claude-sonnet-4 # Für Zusammenfassung
|
||
OPENROUTER_MODEL_FAST=anthropic/claude-haiku-4-5 # Für Skill-Empfehlungen (billiger)
|
||
```
|
||
|
||
---
|
||
|
||
## 10. Fehlerbehandlung
|
||
|
||
| Szenario | Verhalten |
|
||
|----------|-----------|
|
||
| OPENROUTER_API_KEY nicht gesetzt | KI-Buttons nicht anzeigen, kein Auto-Fallback |
|
||
| API-Timeout (> 10s) | Fehlermeldung inline: "KI momentan nicht verfügbar. Bitte manuell ausfüllen." |
|
||
| API-Fehler (5xx) | Gleiche Meldung, kein Absturz |
|
||
| Unbekannte Skills in Empfehlung | Backend filtert Skills die nicht im Katalog sind heraus |
|
||
| Summary zu lang generiert | Backend kürzt auf 200 Zeichen |
|
||
|
||
---
|
||
|
||
**Version:** 1.0
|
||
**Datum:** 2026-04-24
|
||
**Status:** DRAFT
|