diff --git a/llm-api/plan_router.py b/llm-api/plan_router.py index b36effb..e250ca0 100644 --- a/llm-api/plan_router.py +++ b/llm-api/plan_router.py @@ -1,15 +1,16 @@ # -*- coding: utf-8 -*- """ -plan_router.py – v0.12.3 (WP-15) +plan_router.py – v0.12.4 (WP-15) Minimal-CRUD für Plan-Templates & Pläne (POST/GET) + Idempotenz via Fingerprint. -Änderungen ggü. v0.12.0/0.12.1/0.12.2: -- NEU: GET /plan_templates – Liste & Filter (discipline, age_group, target_group, section, goal, keyword) -- NEU: GET /plans – Liste & Filter (created_by, discipline, age_group, target_group, goal, section, created_from/created_to) -- FIX/NEU: POST /plan materialisiert `plan_section_names` für robuste Section-Filter & Index -- Beibeh.: Idempotenz via fingerprint, optionale Strict-Checks (template/exercises) -- Swagger-Doku präzisiert +Änderungen ggü. v0.12.1/0.12.3: +- FIX: POST /plan materialisiert `plan_section_names` im Payload (robuste Section-Filter). +- GET /plans filtert auf `plan_section_names` (statt verschachteltem `sections.name`). +- GET /plan_templates & GET /plans: Filter + Paging + Swagger-Beschreibungen. +- Optional: Strict-Checks (template_id/exercises) via ENV. + +Hinweis: KEYWORD-Index für `plans.plan_section_names` per bootstrap sicherstellen. """ from fastapi import APIRouter, HTTPException, Query from pydantic import BaseModel, Field @@ -325,17 +326,15 @@ def create_plan(p: Plan): if isinstance(payload.get("created_at"), datetime): payload["created_at"] = payload["created_at"].astimezone(timezone.utc).isoformat() # Materialisierte Section-Namen für robuste Filter/Indizes - """ try: - payload["plan_section_names"] = _norm_list([s.get("name", "") for s in (payload.get("sections") or [])]) + payload["plan_section_names"] = _norm_list([ + (s.get("name") or "").strip() for s in (payload.get("sections") or []) if isinstance(s, dict) + ]) except Exception: - payload["plan_section_names"] = _norm_list([s.name for s in (p.sections or [])]) - """ - try: - payload["plan_section_names"] = sorted({ (s.get("name") or "").strip() for s in (payload.get("sections") or []) if s.get("name") }) - except Exception: - payload["plan_section_names"] = sorted({ (s.name or "").strip() for s in (p.sections or []) if getattr(s, "name", None) }) - + payload["plan_section_names"] = _norm_list([ + (getattr(s, "name", "") or "").strip() for s in (p.sections or []) + ]) + vec = _embed(_plan_embed_text(p)) qdrant.upsert(collection_name=PLAN_COLLECTION, points=[PointStruct(id=str(p.id), vector=vec, payload=payload)]) return p @@ -397,7 +396,7 @@ def list_plans( must.append(FieldCondition(key="goals", match=MatchValue(value=goal))) if section: must.append(FieldCondition(key="plan_section_names", match=MatchValue(value=section))) - + flt = Filter(must=must or None) if must else None fetch_n = max(offset + limit, 1)