feat: implement AI custom tag proposals

- AI now suggests dominant notes not in the system list (Part 3: Custom Suggestions)
- Updated TagSelector to show 'Neu anlegen?' buttons for AI-proposed custom tags
- Added suggested_custom_tags to bottles table and metadata schema
- Updated TastingNoteForm to handle both system and custom AI suggestions
This commit is contained in:
2025-12-19 13:20:13 +01:00
parent b2a1d292da
commit 74916aec73
12 changed files with 216 additions and 29 deletions

View File

@@ -33,6 +33,7 @@ export default function TastingNoteForm({ bottleId, sessionId }: TastingNoteForm
const [noseTagIds, setNoseTagIds] = useState<string[]>([]);
const [palateTagIds, setPalateTagIds] = useState<string[]>([]);
const [finishTagIds, setFinishTagIds] = useState<string[]>([]);
const [suggestedTags, setSuggestedTags] = useState<string[]>([]);
const { activeSession } = useSession();
const effectiveSessionId = sessionId || activeSession?.id;
@@ -43,6 +44,17 @@ export default function TastingNoteForm({ bottleId, sessionId }: TastingNoteForm
const { data: buddiesData } = await supabase.from('buddies').select('id, name').order('name');
setBuddies(buddiesData || []);
// Fetch Bottle Suggestions
const { data: bottleData } = await supabase
.from('bottles')
.select('suggested_tags')
.eq('id', bottleId)
.maybeSingle();
if (bottleData?.suggested_tags) {
setSuggestedTags(bottleData.suggested_tags);
}
// If Session ID, fetch session participants and pre-select them
if (effectiveSessionId) {
const { data: participants } = await supabase
@@ -58,7 +70,7 @@ export default function TastingNoteForm({ bottleId, sessionId }: TastingNoteForm
}
};
fetchData();
}, [effectiveSessionId]);
}, [effectiveSessionId, bottleId]);
const toggleBuddy = (id: string) => {
setSelectedBuddyIds(prev =>
@@ -185,6 +197,8 @@ export default function TastingNoteForm({ bottleId, sessionId }: TastingNoteForm
selectedTagIds={noseTagIds}
onToggleTag={toggleNoseTag}
label={t('tasting.nose')}
suggestedTagNames={suggestedTags}
suggestedCustomTagNames={suggestedCustomTags}
/>
<div className="space-y-2">
<label className="text-[10px] font-black text-zinc-400 uppercase tracking-widest block opacity-50">Zusätzliche Notizen</label>
@@ -204,6 +218,8 @@ export default function TastingNoteForm({ bottleId, sessionId }: TastingNoteForm
selectedTagIds={palateTagIds}
onToggleTag={togglePalateTag}
label={t('tasting.palate')}
suggestedTagNames={suggestedTags}
suggestedCustomTagNames={suggestedCustomTags}
/>
<div className="space-y-2">
<label className="text-[10px] font-black text-zinc-400 uppercase tracking-widest block opacity-50">Zusätzliche Notizen</label>
@@ -223,6 +239,8 @@ export default function TastingNoteForm({ bottleId, sessionId }: TastingNoteForm
selectedTagIds={finishTagIds}
onToggleTag={toggleFinishTag}
label={t('tasting.finish')}
suggestedTagNames={suggestedTags}
suggestedCustomTagNames={suggestedCustomTags}
/>
<TagSelector
@@ -230,6 +248,8 @@ export default function TastingNoteForm({ bottleId, sessionId }: TastingNoteForm
selectedTagIds={finishTagIds} // Using finish state for texture for now, or separate if needed
onToggleTag={toggleFinishTag}
label="Textur & Mundgefühl"
suggestedTagNames={suggestedTags}
suggestedCustomTagNames={suggestedCustomTags}
/>
<div className="space-y-2">