shinkan-jinkendo/backend/planning_exercise_expectation.py
Lars 5c882985e0
All checks were successful
Deploy Development / deploy (push) Successful in 41s
Test Suite / pytest-backend (push) Successful in 43s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 13s
Test Suite / k6 /health Baseline (push) Successful in 34s
Test Suite / playwright-tests (push) Successful in 1m15s
Enhance Planning Exercise Functionality and LLM Integration
- Added support for the new planning exercise expectation profile slug in the AI prompt runtime.
- Refactored SQL parameter handling in the planning exercise retrieval process to ensure correct binding for full-text search.
- Updated the planning exercise suggestion logic to incorporate LLM expectation handling, improving the accuracy of exercise recommendations.
- Introduced new functions to determine when to run the LLM expectation pipeline, enhancing the decision-making process for exercise suggestions.
- Incremented version to 0.8.176 and updated changelog to reflect these enhancements in planning AI capabilities.
2026-05-22 23:08:53 +02:00

70 lines
2.7 KiB
Python

"""
Preset „Nächste aus Kontext“: LLM leitet Erwartungsprofil aus Planungskontext ab.
Prompt: planning_exercise_expectation_profile (Migration 074)
"""
from __future__ import annotations
import logging
from typing import Any, Dict, Mapping, Optional, Tuple
from planning_exercise_intent import (
PlanningQueryIntentParsed,
_compact_json,
_load_compact_catalog,
_load_skills_catalog_compact,
parse_planning_query_intent_response,
)
from ai_prompt_runtime import AiPromptUnavailableError, load_and_render_ai_prompt
from openrouter_chat import (
effective_openrouter_model_for_prompt_row,
normalize_openrouter_env,
openrouter_chat_completion,
)
_logger = logging.getLogger("shinkan.planning_exercise_expectation")
def try_build_planning_expectation_from_context(
cur,
*,
heuristic_intent: str,
context_summary: Mapping[str, Any],
target_profile_summary: Mapping[str, Any],
) -> Tuple[Optional[PlanningQueryIntentParsed], bool]:
"""
LLM-Erwartungsprofil für preset_next / leere Anfrage mit Planungsbezug.
Returns (parsed overlay, applied).
"""
api_key, _ = normalize_openrouter_env()
if not api_key:
return None, False
variables = {
"heuristic_intent": heuristic_intent or "suggest_next",
"planning_context_json": _compact_json(dict(context_summary or {})),
"target_profile_json": _compact_json(dict(target_profile_summary or {})),
"skills_catalog_json": _compact_json(_load_skills_catalog_compact(cur)),
"focus_areas_catalog_json": _compact_json(_load_compact_catalog(cur, "focus_areas", "id")),
"training_types_catalog_json": _compact_json(_load_compact_catalog(cur, "training_types", "id")),
"style_directions_catalog_json": _compact_json(_load_compact_catalog(cur, "style_directions", "id")),
"target_groups_catalog_json": _compact_json(_load_compact_catalog(cur, "target_groups", "id")),
}
try:
prow, rendered = load_and_render_ai_prompt(cur, "planning_exercise_expectation_profile", variables)
model = effective_openrouter_model_for_prompt_row(prow)
raw = openrouter_chat_completion(api_key=api_key, model=model, user_content=rendered.text)
parsed = parse_planning_query_intent_response(raw)
if parsed.scenario not in ("preset_next", "continue_plan", "free_search"):
parsed = parsed.model_copy(update={"scenario": "preset_next"})
return parsed, True
except AiPromptUnavailableError:
return None, False
except Exception as exc:
_logger.warning("Planungs-Erwartungsprofil-LLM fehlgeschlagen: %s", exc)
return None, False
__all__ = ["try_build_planning_expectation_from_context"]