feat: zentraler Schalter für Pipeline-Deaktivierung
VORHER: - Pipeline-Deaktivierung war nicht sichtbar im UI - Deaktivierung sollte über Sub-Prompts erfolgen (nicht intuitiv) JETZT: - Zentraler Toggle-Button direkt unter "Mehrstufige Pipeline" - Button-Text: "Gesamte Pipeline aktivieren/deaktivieren" - Visuelles Feedback: Warning-Box wird rot wenn deaktiviert IMPLEMENTIERUNG: Backend (main.py): - Neuer "pipeline" Master-Prompt wird automatisch angelegt - startup_event() ruft init_db() auf - Prompt: slug='pipeline', sort_order=-10 (ganz oben) - Template: 'PIPELINE_MASTER' (nur Steuerung, kein echtes Template) Frontend (Analysis.jsx): - Toggle-Button unter Sektionsüberschrift - Prüft: prompts.find(p=>p.slug==='pipeline')?.active - pipelineAvailable basiert auf diesem Prompt (nicht Sub-Prompts) - Warning-Box wechselt Farbe + Text: * Aktiv: Orange + JSON-Hinweis * Inaktiv: Rot + "Pipeline deaktiviert" VERHALTEN: ✅ Button im Prompts-Tab unter "Mehrstufige Pipeline" ✅ Klar sichtbar: "Gesamte Pipeline deaktivieren" ✅ Pipeline verschwindet von Analyse-Seite wenn deaktiviert ✅ Sub-Prompts bleiben unabhängig editierbar Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
961f905279
commit
c40b30737a
|
|
@ -40,11 +40,34 @@ app.add_middleware(
|
||||||
|
|
||||||
AVATAR_COLORS = ['#1D9E75','#378ADD','#D85A30','#EF9F27','#7F77DD','#D4537E','#639922','#888780']
|
AVATAR_COLORS = ['#1D9E75','#378ADD','#D85A30','#EF9F27','#7F77DD','#D4537E','#639922','#888780']
|
||||||
|
|
||||||
|
@app.on_event("startup")
|
||||||
|
async def startup_event():
|
||||||
|
"""Run migrations and initialization on startup."""
|
||||||
|
init_db()
|
||||||
|
|
||||||
def init_db():
|
def init_db():
|
||||||
"""Initialize database - Schema is loaded by startup.sh"""
|
"""Initialize database - Schema is loaded by startup.sh"""
|
||||||
# Schema loading and migration handled by startup.sh
|
# Schema loading and migration handled by startup.sh
|
||||||
# This function kept for backwards compatibility
|
# This function kept for backwards compatibility
|
||||||
pass
|
|
||||||
|
# Ensure "pipeline" master prompt exists
|
||||||
|
with get_db() as conn:
|
||||||
|
cur = get_cursor(conn)
|
||||||
|
cur.execute("SELECT COUNT(*) as count FROM ai_prompts WHERE slug='pipeline'")
|
||||||
|
if cur.fetchone()['count'] == 0:
|
||||||
|
cur.execute("""
|
||||||
|
INSERT INTO ai_prompts (slug, name, description, template, active, sort_order)
|
||||||
|
VALUES (
|
||||||
|
'pipeline',
|
||||||
|
'Mehrstufige Gesamtanalyse',
|
||||||
|
'Master-Schalter für die gesamte Pipeline. Deaktiviere diese Analyse, um die Pipeline komplett zu verstecken.',
|
||||||
|
'PIPELINE_MASTER',
|
||||||
|
true,
|
||||||
|
-10
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
conn.commit()
|
||||||
|
print("✓ Pipeline master prompt created")
|
||||||
|
|
||||||
# ── Helper: get profile_id from header ───────────────────────────────────────
|
# ── Helper: get profile_id from header ───────────────────────────────────────
|
||||||
def get_pid(x_profile_id: Optional[str] = Header(default=None)) -> str:
|
def get_pid(x_profile_id: Optional[str] = Header(default=None)) -> str:
|
||||||
|
|
|
||||||
|
|
@ -179,9 +179,9 @@ export default function Analysis() {
|
||||||
|
|
||||||
const activePrompts = prompts.filter(p=>p.active && !p.slug.startsWith('pipeline_'))
|
const activePrompts = prompts.filter(p=>p.active && !p.slug.startsWith('pipeline_'))
|
||||||
|
|
||||||
// Pipeline is available only if ALL pipeline sub-prompts are active
|
// Pipeline is available if the "pipeline" prompt is active
|
||||||
const pipelineSlugs = ['pipeline_body','pipeline_nutrition','pipeline_activity','pipeline_synthesis','pipeline_goals']
|
const pipelinePrompt = prompts.find(p=>p.slug==='pipeline')
|
||||||
const pipelineAvailable = pipelineSlugs.every(slug => prompts.find(p=>p.slug===slug)?.active)
|
const pipelineAvailable = pipelinePrompt?.active ?? true // Default to true if not found (backwards compatibility)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -386,15 +386,47 @@ export default function Analysis() {
|
||||||
))}
|
))}
|
||||||
|
|
||||||
{/* Pipeline prompts */}
|
{/* Pipeline prompts */}
|
||||||
|
<div style={{display:'flex',alignItems:'center',justifyContent:'space-between',margin:'20px 0 8px'}}>
|
||||||
<div style={{fontSize:12,fontWeight:700,color:'var(--text3)',
|
<div style={{fontSize:12,fontWeight:700,color:'var(--text3)',
|
||||||
textTransform:'uppercase',letterSpacing:'0.05em',margin:'20px 0 8px'}}>
|
textTransform:'uppercase',letterSpacing:'0.05em'}}>
|
||||||
Mehrstufige Pipeline
|
Mehrstufige Pipeline
|
||||||
</div>
|
</div>
|
||||||
<div style={{padding:'10px 12px',background:'var(--warn-bg)',borderRadius:8,
|
{(() => {
|
||||||
fontSize:12,color:'var(--warn-text)',marginBottom:12,lineHeight:1.6}}>
|
const pipelinePrompt = prompts.find(p=>p.slug==='pipeline')
|
||||||
⚠️ <strong>Hinweis:</strong> Pipeline-Stage-1-Prompts müssen valides JSON zurückgeben.
|
return pipelinePrompt && (
|
||||||
Halte das JSON-Format im Prompt erhalten. Stage 2 + 3 können frei angepasst werden.
|
<button className="btn btn-secondary" style={{padding:'5px 12px',fontSize:12}}
|
||||||
|
onClick={()=>{
|
||||||
|
const token = localStorage.getItem('bodytrack_token')||''
|
||||||
|
fetch(`/api/prompts/${pipelinePrompt.id}`,{
|
||||||
|
method:'PUT',
|
||||||
|
headers:{'Content-Type':'application/json','X-Auth-Token':token},
|
||||||
|
body:JSON.stringify({active:!pipelinePrompt.active})
|
||||||
|
}).then(loadAll)
|
||||||
|
}}>
|
||||||
|
{pipelinePrompt.active ? 'Gesamte Pipeline deaktivieren' : 'Gesamte Pipeline aktivieren'}
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
})()}
|
||||||
</div>
|
</div>
|
||||||
|
{(() => {
|
||||||
|
const pipelinePrompt = prompts.find(p=>p.slug==='pipeline')
|
||||||
|
const isPipelineActive = pipelinePrompt?.active ?? true
|
||||||
|
return (
|
||||||
|
<div style={{padding:'10px 12px',
|
||||||
|
background: isPipelineActive ? 'var(--warn-bg)' : '#FCEBEB',
|
||||||
|
borderRadius:8,fontSize:12,
|
||||||
|
color: isPipelineActive ? 'var(--warn-text)' : '#D85A30',
|
||||||
|
marginBottom:12,lineHeight:1.6}}>
|
||||||
|
{isPipelineActive ? (
|
||||||
|
<>⚠️ <strong>Hinweis:</strong> Pipeline-Stage-1-Prompts müssen valides JSON zurückgeben.
|
||||||
|
Halte das JSON-Format im Prompt erhalten. Stage 2 + 3 können frei angepasst werden.</>
|
||||||
|
) : (
|
||||||
|
<>⏸ <strong>Pipeline deaktiviert:</strong> Die mehrstufige Gesamtanalyse ist aktuell nicht verfügbar.
|
||||||
|
Aktiviere sie mit dem Schalter oben, um sie auf der Analyse-Seite zu nutzen.</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})()}
|
||||||
{pipelinePrompts.map(p=>{
|
{pipelinePrompts.map(p=>{
|
||||||
const isJson = jsonSlugs.includes(p.slug)
|
const isJson = jsonSlugs.includes(p.slug)
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user