"use client"; import { useState } from "react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { toast } from "sonner"; import { useTranslations } from "next-intl"; type Provider = "openai" | "anthropic" | "openrouter" | "ollama" | ""; type UseCase = { key: "text" | "vision" | "mealPlan"; labelKey: "useCaseText" | "useCaseVision" | "useCaseMealPlan"; descriptionKey: "useCaseTextDesc" | "useCaseVisionDesc" | "useCaseMealPlanDesc"; }; const USE_CASES: UseCase[] = [ { key: "text", labelKey: "useCaseText", descriptionKey: "useCaseTextDesc" }, { key: "vision", labelKey: "useCaseVision", descriptionKey: "useCaseVisionDesc" }, { key: "mealPlan", labelKey: "useCaseMealPlan", descriptionKey: "useCaseMealPlanDesc" }, ]; const PRESET_MODELS: Record = { openai: { label: "OpenAI", models: [ { value: "gpt-4o", label: "GPT-4o" }, { value: "gpt-4o-mini", label: "GPT-4o mini (faster)" }, { value: "o3-mini", label: "o3-mini (reasoning)" }, { value: "gpt-4-turbo", label: "GPT-4 Turbo" }, ], }, anthropic: { label: "Anthropic", models: [ { value: "claude-sonnet-4-6", label: "Claude Sonnet 4.6" }, { value: "claude-opus-4-8", label: "Claude Opus 4.8 (most capable)" }, { value: "claude-haiku-4-5-20251001", label: "Claude Haiku 4.5 (fastest)" }, ], }, }; type Prefs = { textProvider?: string | null; textModel?: string | null; visionProvider?: string | null; visionModel?: string | null; mealPlanProvider?: string | null; mealPlanModel?: string | null; }; export function ModelPrefsForm({ initialPrefs }: { initialPrefs: Prefs | null }) { const t = useTranslations("settingsForm"); const [prefs, setPrefs] = useState(initialPrefs ?? {}); const [saving, setSaving] = useState(false); function setField(field: keyof Prefs, value: string | null) { setPrefs((prev) => ({ ...prev, [field]: value || null })); } async function handleSave() { setSaving(true); try { const res = await fetch("/api/v1/users/me/model-prefs", { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify(prefs), }); if (!res.ok) throw new Error("Save failed"); toast.success(t("modelSaved")); } catch { toast.error(t("modelSaveFailed")); } finally { setSaving(false); } } return (
{USE_CASES.map(({ key, labelKey, descriptionKey }) => { const providerKey = `${key}Provider` as keyof Prefs; const modelKey = `${key}Model` as keyof Prefs; const provider = (prefs[providerKey] ?? "") as Provider; const model = (prefs[modelKey] ?? "") as string; const presets = provider && PRESET_MODELS[provider]?.models; return (

{t(labelKey)}

{t(descriptionKey)}

{presets ? ( ) : ( setField(modelKey, e.target.value)} disabled={!provider} /> )}
); })}
); }