""" POST /api/planning/exercise-suggest — planungsgebundene Übungssuche (Hybrid + Profil + optional LLM-Rerank). """ from fastapi import APIRouter, Depends from db import get_db, get_cursor from tenant_context import TenantContext, get_tenant_context from planning_exercise_suggest import PlanningExerciseSuggestRequest, suggest_planning_exercises from planning_exercise_path_builder import ProgressionPathSuggestRequest, suggest_progression_path from account_lifecycle import assert_min_account_state from capabilities import probe_capability from club_features import ( consume_club_feature_with_usage, merge_feature_usage_into_response, probe_club_feature_access, resolve_club_id_for_probe, ) router = APIRouter(prefix="/api/planning", tags=["planning_exercise_suggest"]) @router.post("/exercise-suggest") def post_planning_exercise_suggest( body: PlanningExerciseSuggestRequest, tenant: TenantContext = Depends(get_tenant_context), ): uses_ai = body.include_llm_intent or body.include_llm_rank club_id = resolve_club_id_for_probe(tenant) if uses_ai else None if uses_ai: assert_min_account_state(tenant, "active_member", endpoint="POST /planning/exercise-suggest") probe_capability( tenant, "planning.ai.suggest", action="planning_suggest", club_id=club_id, endpoint="POST /planning/exercise-suggest", ) probe_club_feature_access( feature_id="ai_calls", action="planning_suggest", club_id=club_id, profile_id=tenant.profile_id, portal_role=tenant.global_role, endpoint="POST /planning/exercise-suggest", tenant=tenant, ) with get_db() as conn: cur = get_cursor(conn) result = suggest_planning_exercises(cur, tenant=tenant, body=body) if uses_ai: usage = consume_club_feature_with_usage( feature_id="ai_calls", club_id=club_id, profile_id=tenant.profile_id, portal_role=tenant.global_role, action="planning_suggest", cur=cur, tenant=tenant, conn=conn, ) result = merge_feature_usage_into_response(result, usage) return result @router.post("/progression-path-suggest") def post_progression_path_suggest( body: ProgressionPathSuggestRequest, tenant: TenantContext = Depends(get_tenant_context), ): uses_ai = ( body.include_llm_intent or body.include_llm_path_qa or body.include_ai_gap_fill ) club_id = resolve_club_id_for_probe(tenant) if uses_ai else None if uses_ai: assert_min_account_state( tenant, "active_member", endpoint="POST /planning/progression-path-suggest" ) probe_capability( tenant, "planning.ai.progression_path", action="progression_path_suggest", club_id=club_id, endpoint="POST /planning/progression-path-suggest", ) probe_club_feature_access( feature_id="ai_calls", action="progression_path_suggest", club_id=club_id, profile_id=tenant.profile_id, portal_role=tenant.global_role, endpoint="POST /planning/progression-path-suggest", tenant=tenant, ) with get_db() as conn: cur = get_cursor(conn) result = suggest_progression_path(cur, tenant=tenant, body=body) if uses_ai: usage = consume_club_feature_with_usage( feature_id="ai_calls", club_id=club_id, profile_id=tenant.profile_id, portal_role=tenant.global_role, action="progression_path_suggest", cur=cur, tenant=tenant, conn=conn, ) result = merge_feature_usage_into_response(result, usage) return result