From 961f905279bd3512e90a92b4fabef848e1337513 Mon Sep 17 00:00:00 2001 From: Lars Date: Thu, 19 Mar 2026 07:47:59 +0100 Subject: [PATCH] fix: drei kritische Bugs in KI-Analysen behoben MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PROBLEM 1: Deaktivierte Prompts auf Verlaufsseiten sichtbar - Deaktivierte Analysen (z.B. "Komposition") wurden auf Verlaufsseiten (Körper, Ernährung, etc.) als klickbare Buttons angezeigt FIX: - Prompts werden jetzt in History.jsx geladen (api.listPrompts) - filterActiveSlugs() filtert nur aktive Prompts - InsightBox zeigt nur Buttons für aktive Analysen PROBLEM 2: Pipeline konnte nicht deaktiviert werden - Mehrstufige Gesamtanalyse war immer sichtbar FIX: - Pipeline ist nur verfügbar wenn ALLE Sub-Prompts aktiv sind - Prüft: pipeline_body, pipeline_nutrition, pipeline_activity, pipeline_synthesis, pipeline_goals - Deaktiviere einen Sub-Prompt → Pipeline verschwindet PROBLEM 3: Fehler "z.text is not a function" - Nach Analyse-Ausführung auf Verlaufsseiten kam Fehler - Code behandelte api.runInsight() wie fetch()-Response FIX: - api.runInsight() gibt bereits JSON zurück, nicht Response - Entfernte fehlerhafte if(!r.ok) und await r.text() - Error-Handling wie in Analysis.jsx (catch e.message) DATEIEN: - frontend/src/pages/History.jsx: alle 3 Fixes - frontend/src/pages/Analysis.jsx: Pipeline-Verfügbarkeit Co-Authored-By: Claude Opus 4.6 --- frontend/src/pages/Analysis.jsx | 60 ++++++++++++++++++--------------- frontend/src/pages/History.jsx | 39 ++++++++++++--------- 2 files changed, 57 insertions(+), 42 deletions(-) diff --git a/frontend/src/pages/Analysis.jsx b/frontend/src/pages/Analysis.jsx index 27377be..4c55d33 100644 --- a/frontend/src/pages/Analysis.jsx +++ b/frontend/src/pages/Analysis.jsx @@ -179,6 +179,10 @@ export default function Analysis() { const activePrompts = prompts.filter(p=>p.active && !p.slug.startsWith('pipeline_')) + // Pipeline is available only if ALL pipeline sub-prompts are active + const pipelineSlugs = ['pipeline_body','pipeline_nutrition','pipeline_activity','pipeline_synthesis','pipeline_goals'] + const pipelineAvailable = pipelineSlugs.every(slug => prompts.find(p=>p.slug===slug)?.active) + return (

KI-Analyse

@@ -221,36 +225,38 @@ export default function Analysis() {
)} - {/* Pipeline button */} -
-
-
-
🔬 Mehrstufige Gesamtanalyse
-
- 3 spezialisierte KI-Calls parallel (Körper + Ernährung + Aktivität), - dann Synthese + Zielabgleich. Detaillierteste Auswertung. -
- {allInsights.find(i=>i.scope==='pipeline') && ( -
- Letzte Analyse: {dayjs(allInsights.find(i=>i.scope==='pipeline').created).format('DD.MM.YYYY, HH:mm')} + {/* Pipeline button - only if all sub-prompts are active */} + {pipelineAvailable && ( +
+
+
+
🔬 Mehrstufige Gesamtanalyse
+
+ 3 spezialisierte KI-Calls parallel (Körper + Ernährung + Aktivität), + dann Synthese + Zielabgleich. Detaillierteste Auswertung.
- )} + {allInsights.find(i=>i.scope==='pipeline') && ( +
+ Letzte Analyse: {dayjs(allInsights.find(i=>i.scope==='pipeline').created).format('DD.MM.YYYY, HH:mm')} +
+ )} +
+ + {!canUseAI &&
🔒 KI nicht freigeschaltet
}
- - {!canUseAI &&
🔒 KI nicht freigeschaltet
} + {pipelineLoading && ( +
+ ⚡ Stufe 1: 3 parallele Analyse-Calls… dann Synthese… dann Zielabgleich +
+ )}
- {pipelineLoading && ( -
- ⚡ Stufe 1: 3 parallele Analyse-Calls… dann Synthese… dann Zielabgleich -
- )} -
+ )} {!canUseAI && (
)} -
) } // ── Nutrition Section ───────────────────────────────────────────────────────── -function NutritionSection({ nutrition, weights, profile, insights, onRequest, loadingSlug }) { +function NutritionSection({ nutrition, weights, profile, insights, onRequest, loadingSlug, filterActiveSlugs }) { const [period, setPeriod] = useState(30) if (!nutrition?.length) return ( @@ -579,13 +579,13 @@ function NutritionSection({ nutrition, weights, profile, insights, onRequest, lo
BEWERTUNG
{macroRules.map((item,i)=>)}
- +
) } // ── Activity Section ────────────────────────────────────────────────────────── -function ActivitySection({ activities, insights, onRequest, loadingSlug }) { +function ActivitySection({ activities, insights, onRequest, loadingSlug, filterActiveSlugs }) { const [period, setPeriod] = useState(30) if (!activities?.length) return ( @@ -657,13 +657,13 @@ function ActivitySection({ activities, insights, onRequest, loadingSlug }) {
BEWERTUNG
{actRules.map((item,i)=>)}
- + ) } // ── Correlation Section ─────────────────────────────────────────────────────── -function CorrelationSection({ corrData, insights, profile, onRequest, loadingSlug }) { +function CorrelationSection({ corrData, insights, profile, onRequest, loadingSlug, filterActiveSlugs }) { const filtered = (corrData||[]).filter(d=>d.kcal&&d.weight) if (filtered.length < 5) return ( @@ -852,7 +852,7 @@ function CorrelationSection({ corrData, insights, profile, onRequest, loadingSlu )} - + ) } @@ -903,6 +903,7 @@ export default function History() { const [activities, setActivities] = useState([]) const [corrData, setCorrData] = useState([]) const [insights, setInsights] = useState([]) + const [prompts, setPrompts] = useState([]) const [profile, setProfile] = useState(null) const [loading, setLoading] = useState(true) const [loadingSlug,setLoadingSlug]= useState(null) @@ -911,10 +912,12 @@ export default function History() { api.listWeight(365), api.listCaliper(), api.listCirc(), api.listNutrition(90), api.listActivity(200), api.nutritionCorrelations(), api.latestInsights(), api.getProfile(), - ]).then(([w,ca,ci,n,a,corr,ins,p])=>{ + api.listPrompts(), + ]).then(([w,ca,ci,n,a,corr,ins,p,pr])=>{ setWeights(w); setCalipers(ca); setCircs(ci) setNutrition(n); setActivities(a); setCorrData(corr) setInsights(Array.isArray(ins)?ins:[]); setProfile(p) + setPrompts(Array.isArray(pr)?pr:[]) setLoading(false) }) @@ -923,17 +926,23 @@ export default function History() { const requestInsight = async (slug) => { setLoadingSlug(slug) try { - const pid=localStorage.getItem('bodytrack_active_profile')||'' - const r=await api.runInsight(slug) - if(!r.ok) throw new Error(await r.text()) - const ins=await api.latestInsights() + const result = await api.runInsight(slug) + // result is already JSON, not a Response object + const ins = await api.latestInsights() setInsights(Array.isArray(ins)?ins:[]) - } catch(e){ alert('KI-Fehler: '+e.message) } + } catch(e){ + alert('KI-Fehler: '+e.message) + } finally{ setLoadingSlug(null) } } if(loading) return
- const sp={insights,onRequest:requestInsight,loadingSlug} + + // Filter active prompts + const activeSlugs = prompts.filter(p=>p.active).map(p=>p.slug) + const filterActiveSlugs = (slugs) => slugs.filter(s=>activeSlugs.includes(s)) + + const sp={insights,onRequest:requestInsight,loadingSlug,filterActiveSlugs} return (