import { useEffect, useRef, useState } from 'react' import { type FeedbackDimension, type FeedbackDimensionPrompt, loadFeedbackStructure, listFeedbackDimensionPrompts, updateFeedbackDimensionPrompt, resetAllDimensionPromptsToDefault, getOrSeedDefaultDimensionPromptTemplate, saveDefaultDimensionPromptTemplate, getOrSeedDefaultCategoryPromptTemplate, saveDefaultCategoryPromptTemplate, getOrSeedCriterionTaggingPromptTemplate, saveCriterionTaggingPromptTemplate, getOrSeedChecklistTaggingPromptTemplate, saveChecklistTaggingPromptTemplate, } from '../db' import { AI_CONFIG } from '../config/constants' import { getAiSettings, saveAiSettings } from '../utils/aiClient' export default function AiPromptConfig() { const [dimensions, setDimensions] = useState([]) const [prompts, setPrompts] = useState([]) const [defaultTemplate, setDefaultTemplate] = useState('') const [defaultExpanded, setDefaultExpanded] = useState(false) const [defaultSaved, setDefaultSaved] = useState(false) const [categoryTemplate, setCategoryTemplate] = useState('') const [categoryExpanded, setCategoryExpanded] = useState(false) const [categorySaved, setCategorySaved] = useState(false) const [taggingTemplate, setTaggingTemplate] = useState('') const [taggingExpanded, setTaggingExpanded] = useState(false) const [taggingSaved, setTaggingSaved] = useState(false) const [checklistTaggingTemplate, setChecklistTaggingTemplate] = useState('') const [checklistTaggingExpanded, setChecklistTaggingExpanded] = useState(false) const [checklistTaggingSaved, setChecklistTaggingSaved] = useState(false) const [expanded, setExpanded] = useState>(new Set()) const [savedDimId, setSavedDimId] = useState(null) const [bulkResetMsg, setBulkResetMsg] = useState('') const saveTimer = useRef>>(new Map()) const [aiKey, setAiKey] = useState(getAiSettings().apiKey) const [aiModel, setAiModel] = useState(getAiSettings().model) const [aiSaved, setAiSaved] = useState(false) const load = async () => { const [structure, promptRows, defTemplate, catTemplate, taggingTpl, checklistTaggingTpl] = await Promise.all([ loadFeedbackStructure(), listFeedbackDimensionPrompts(), getOrSeedDefaultDimensionPromptTemplate(), getOrSeedDefaultCategoryPromptTemplate(), getOrSeedCriterionTaggingPromptTemplate(), getOrSeedChecklistTaggingPromptTemplate(), ]) setDimensions([...structure.dimensions].sort((a, b) => a.order - b.order)) setPrompts(promptRows) setDefaultTemplate(defTemplate) setCategoryTemplate(catTemplate) setTaggingTemplate(taggingTpl) setChecklistTaggingTemplate(checklistTaggingTpl) } useEffect(() => { load() }, []) const getPrompt = (dimId: number) => prompts.find(p => p.dimensionId === dimId) const saveTemplate = (dimId: number, value: string) => { setPrompts(prev => prev.map(p => p.dimensionId === dimId ? { ...p, promptTemplate: value } : p)) const prevTimer = saveTimer.current.get(dimId) if (prevTimer) clearTimeout(prevTimer) saveTimer.current.set(dimId, setTimeout(async () => { const existing = getPrompt(dimId) if (!existing?.id) return await updateFeedbackDimensionPrompt(existing.id, { promptTemplate: value }) setSavedDimId(dimId) setTimeout(() => setSavedDimId(null), 2000) }, 600)) } const resetToDefault = async (dimId: number) => { const existing = getPrompt(dimId) if (!existing?.id) return await updateFeedbackDimensionPrompt(existing.id, { promptTemplate: defaultTemplate }) setPrompts(prev => prev.map(p => p.dimensionId === dimId ? { ...p, promptTemplate: defaultTemplate } : p)) } const resetAllToDefault = async () => { if (!confirm('Alle Dimension-Prompts wirklich auf den Standard (1–10) setzen? Individuelle Anpassungen gehen verloren.')) return const { updated } = await resetAllDimensionPromptsToDefault() const promptRows = await listFeedbackDimensionPrompts() setPrompts(promptRows) setBulkResetMsg(`${updated} Dimension-Prompt(s) auf Standard gesetzt.`) setTimeout(() => setBulkResetMsg(''), 4000) } const saveDefaultTemplate = (value: string) => { setDefaultTemplate(value) const prevTimer = saveTimer.current.get('default') if (prevTimer) clearTimeout(prevTimer) saveTimer.current.set('default', setTimeout(async () => { await saveDefaultDimensionPromptTemplate(value) setDefaultSaved(true) setTimeout(() => setDefaultSaved(false), 2000) }, 600)) } const saveCategoryTemplate = (value: string) => { setCategoryTemplate(value) const prevTimer = saveTimer.current.get('category') if (prevTimer) clearTimeout(prevTimer) saveTimer.current.set('category', setTimeout(async () => { await saveDefaultCategoryPromptTemplate(value) setCategorySaved(true) setTimeout(() => setCategorySaved(false), 2000) }, 600)) } const resetTaggingToDefault = async () => { const def = AI_CONFIG.defaultCriterionTaggingPromptTemplate await saveCriterionTaggingPromptTemplate(def) setTaggingTemplate(def) } const resetChecklistTaggingToDefault = async () => { const def = AI_CONFIG.defaultChecklistTaggingPromptTemplate await saveChecklistTaggingPromptTemplate(def) setChecklistTaggingTemplate(def) } const saveTaggingTemplate = (value: string) => { setTaggingTemplate(value) const prevTimer = saveTimer.current.get('tagging') if (prevTimer) clearTimeout(prevTimer) saveTimer.current.set('tagging', setTimeout(async () => { await saveCriterionTaggingPromptTemplate(value) setTaggingSaved(true) setTimeout(() => setTaggingSaved(false), 2000) }, 600)) } const saveChecklistTaggingTemplate = (value: string) => { setChecklistTaggingTemplate(value) const prevTimer = saveTimer.current.get('checklistTagging') if (prevTimer) clearTimeout(prevTimer) saveTimer.current.set('checklistTagging', setTimeout(async () => { await saveChecklistTaggingPromptTemplate(value) setChecklistTaggingSaved(true) setTimeout(() => setChecklistTaggingSaved(false), 2000) }, 600)) } return (

KI-Feedback (Kaskade)

Stufe A: ein Call pro Kategorie (globaler Kategorie-Prompt). Stufe B: ein Call pro Dimension (Verdichtung aus Kategorie-Ergebnissen — pro Dimension editierbar unten).

OpenRouter API-Key

Wird lokal im Browser gespeichert (localStorage) — nötig für KI-Feedback und „Vorschläge analysieren". Key von{' '} openrouter.ai.

setAiKey(e.target.value)} /> {aiSaved && (
Gespeichert.
)}
{/* Kategorie-Prompt Stufe A */}
{categoryExpanded && (

Wird für jede Kategorie einzeln aufgerufen. Der Trend-Vorschlag aus Meetings wird im Prompt vorgegeben; die KI bestätigt oder passt maximal ±1 an.