shinkan-jinkendo/backend/migrations/068_ai_skill_retrieval_profiles.sql
Lars 294b09a5d9
All checks were successful
Deploy Development / deploy (push) Successful in 41s
Test Suite / pytest-backend (push) Successful in 38s
Test Suite / lint-backend (push) Successful in 1s
Test Suite / build-frontend (push) Successful in 12s
Test Suite / k6 /health Baseline (push) Successful in 34s
Test Suite / playwright-tests (push) Successful in 1m13s
Implement AI Skill Retrieval Profiles and Enhance Exercise AI Functionality
- Introduced migration 068 for `ai_skill_retrieval_profiles`, enabling configurable weights and quotes for skill catalog prioritization in exercise AI suggestions.
- Updated the `POST /api/exercises/ai/suggest` endpoint to include an optional `focus_areas_context` field, allowing for enhanced context in AI-generated suggestions.
- Enhanced the `exercise_ai` module to utilize context-based skill selection, incorporating scoring, category caps, and keyword patches for improved AI responses.
- Updated the ExerciseFormPageRoot component to pass focus area context to the AI suggestion API, streamlining user interaction with AI-generated content.
- Incremented version numbers in `backend/version.py` to reflect the latest changes and ensure accurate tracking in the changelog.
2026-05-22 09:49:08 +02:00

126 lines
4.0 KiB
SQL

-- Migration 068: KI Skill-Retrieval-Profile pro Fokusbereich (+ Standardprofil)
-- Purpose: Gewichtungen/Quota fuer exercise_ai Skill-Katalog (OpenRouter Kontext)
CREATE TABLE IF NOT EXISTS ai_skill_retrieval_profiles (
id SERIAL PRIMARY KEY,
focus_area_id INT REFERENCES focus_areas(id) ON DELETE CASCADE,
is_default BOOLEAN NOT NULL DEFAULT FALSE,
name VARCHAR(200) NOT NULL,
description TEXT,
active BOOLEAN NOT NULL DEFAULT TRUE,
config JSONB NOT NULL DEFAULT '{}'::jsonb,
updated_at TIMESTAMP DEFAULT NOW()
);
CREATE UNIQUE INDEX IF NOT EXISTS ux_ai_skill_retrieval_profile_focus_area
ON ai_skill_retrieval_profiles (focus_area_id)
WHERE focus_area_id IS NOT NULL AND active = TRUE;
CREATE UNIQUE INDEX IF NOT EXISTS ux_ai_skill_retrieval_profile_default_only
ON ai_skill_retrieval_profiles (is_default)
WHERE is_default IS TRUE AND active = TRUE;
COMMENT ON TABLE ai_skill_retrieval_profiles IS
'Gewichte/Quota fuer Skill-Katalog in exercise_ai; optional gebunden an focus_areas, genau eine is_default=TRUE';
INSERT INTO ai_skill_retrieval_profiles (focus_area_id, is_default, name, description, active, config)
VALUES (
NULL,
TRUE,
'Standard',
'Kein/Undefinierter Fokusbereich: neutrale Gewichte mit sanften Caps auf sehr breite Unterkategorien.',
TRUE,
'{
"version": 1,
"importance_multiplier": 1,
"text_overlap_bonus": 2,
"main_slug_weights": { "karate": 1, "allgemeine": 1 },
"category_slug_weights": {},
"category_max_share": {
"kondition": 0.38,
"koordination": 0.35
},
"main_min_share": {},
"description_plain_max_len": 160,
"karate_relevance_max_len": 72,
"keyword_overrides": [
{
"keywords_any": ["rollenspiel", "szenario", "deesk", "diskussion"],
"case_insensitive": true,
"patch": {
"category_slug_weights": {
"psychische_faehigkeiten": 1.65,
"soziale_faehigkeiten": 1.65,
"kognition": 1.4
},
"category_max_share": {
"kondition": 0.08,
"koordination": 0.1
}
}
},
{
"keywords_any": ["befreiung", "haltegriff", "greifer", "umklammer"],
"case_insensitive": true,
"patch": {
"category_slug_weights": {
"selbstverteidigung": 2.2,
"koordination": 0.9
},
"main_slug_weights": { "karate": 1.35 }
}
}
]
}'::jsonb
);
INSERT INTO ai_skill_retrieval_profiles (focus_area_id, is_default, name, description, active, config)
SELECT
fa.id,
FALSE,
'Gewaltschutz',
'Kaum klassische Sportfaehigkeit; Gewicht auf Deeskalation, Kognition/Soziales; SV-Schwerpunkt per Keywords verstaerken.',
TRUE,
'{
"version": 1,
"importance_multiplier": 1,
"text_overlap_bonus": 2.25,
"main_slug_weights": { "karate": 1.08, "allgemeine": 1.06 },
"category_slug_weights": {
"kognition": 1.72,
"psychische_faehigkeiten": 1.78,
"soziale_faehigkeiten": 1.78,
"selbstverteidigung": 1.82,
"kondition": 0.32,
"koordination": 0.4
},
"category_max_share": {
"kondition": 0.12,
"koordination": 0.16
},
"main_min_share": {},
"description_plain_max_len": 150,
"karate_relevance_max_len": 0,
"keyword_overrides": [
{
"keywords_any": ["befreiung", "haltegriff", "greifer"],
"case_insensitive": true,
"patch": {
"category_slug_weights": {
"selbstverteidigung": 3.25,
"koordination": 1.08
},
"main_slug_weights": { "karate": 1.5 }
}
}
]
}'::jsonb
FROM focus_areas fa
WHERE fa.name = 'Gewaltschutz'
AND (fa.status IS NULL OR fa.status = 'active')
AND NOT EXISTS (
SELECT 1 FROM ai_skill_retrieval_profiles p
WHERE p.focus_area_id = fa.id AND p.active = TRUE
)
LIMIT 1;