"use client"; import { useState } from "react"; import { toast } from "sonner"; import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { testAiConnection, saveAiConfig } from "@/lib/actions/ai"; import type { AiSettingsView } from "@/lib/ai-settings"; /** Lets an admin point the site at an OpenAI-compatible endpoint (e.g. * OpenWebUI): a URL, a key, and -- once a test confirms it works -- which * of the provider's models to use for AI generation features. */ export function AiSettingsCard({ initial }: { initial: AiSettingsView }) { const [apiUrl, setApiUrl] = useState(initial.apiUrl ?? ""); // Never prefilled with the real key -- the server never sends it back. // A blank field on save means "keep the key that's already stored". const [apiKey, setApiKey] = useState(""); const [model, setModel] = useState(initial.model ?? ""); // Seeded with just the saved model (if any) so the picker isn't empty // on first load -- a fresh "Test connection" replaces this with the // provider's real, current list. const [models, setModels] = useState(initial.model ? [initial.model] : []); const [hasApiKey, setHasApiKey] = useState(initial.hasApiKey); const [testing, setTesting] = useState(false); const [saving, setSaving] = useState(false); async function handleTest() { setTesting(true); const result = await testAiConnection(apiUrl, apiKey); setTesting(false); if (result.error) { toast.error(result.error); return; } const found = result.models ?? []; setModels(found); setModel((prev) => (found.includes(prev) ? prev : found[0] ?? "")); toast.success(`Connected -- found ${found.length} model${found.length === 1 ? "" : "s"}.`); } async function handleSave() { setSaving(true); const result = await saveAiConfig({ apiUrl, apiKey, model }); setSaving(false); if (result.error) { toast.error(result.error); return; } if (apiKey.trim()) setHasApiKey(true); setApiKey(""); // saved -- a blank field means "unchanged" from here on toast.success("AI settings saved."); } return ( AI generation Connect an OpenAI-compatible endpoint (e.g. OpenWebUI) to power AI generation features on the site.
setApiUrl(e.target.value)} placeholder="https://your-openwebui-host/api/v1" />
setApiKey(e.target.value)} placeholder={hasApiKey ? "Unchanged -- leave blank to keep the saved key" : "sk-…"} autoComplete="off" />
); }