"use client"; import { ActionButton } from "@/components/ui/action-button"; import { Form, FormControl, FormField, FormItem, FormMessage, } from "@/components/ui/form"; import { FullPageSpinner } from "@/components/ui/full-page-spinner"; import { Input } from "@/components/ui/input"; import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { toast } from "@/components/ui/use-toast"; import { useClientConfig } from "@/lib/clientConfig"; import { api } from "@/lib/trpc"; import { zodResolver } from "@hookform/resolvers/zod"; import { Plus, Save, Trash2 } from "lucide-react"; import { useForm } from "react-hook-form"; import { z } from "zod"; import { buildImagePrompt, buildTextPrompt } from "@hoarder/shared/prompts"; import { zNewPromptSchema, ZPrompt, zUpdatePromptSchema, } from "@hoarder/shared/types/prompts"; export function PromptEditor() { const apiUtils = api.useUtils(); const form = useForm>({ resolver: zodResolver(zNewPromptSchema), defaultValues: { text: "", appliesTo: "all", }, }); const { mutateAsync: createPrompt, isPending: isCreating } = api.prompts.create.useMutation({ onSuccess: () => { toast({ description: "Prompt has been created!", }); apiUtils.prompts.list.invalidate(); }, }); return (
{ await createPrompt(value); form.resetField("text"); })} > { return ( ); }} /> { return ( ); }} /> Add ); } export function PromptRow({ prompt }: { prompt: ZPrompt }) { const apiUtils = api.useUtils(); const { mutateAsync: updatePrompt, isPending: isUpdating } = api.prompts.update.useMutation({ onSuccess: () => { toast({ description: "Prompt has been updated!", }); apiUtils.prompts.list.invalidate(); }, }); const { mutate: deletePrompt, isPending: isDeleting } = api.prompts.delete.useMutation({ onSuccess: () => { toast({ description: "Prompt has been deleted!", }); apiUtils.prompts.list.invalidate(); }, }); const form = useForm>({ resolver: zodResolver(zUpdatePromptSchema), defaultValues: { promptId: prompt.id, text: prompt.text, appliesTo: prompt.appliesTo, }, }); return (
{ await updatePrompt(value); })} > { return ( ); }} /> { return ( ); }} /> { return ( ); }} /> Save deletePrompt({ promptId: prompt.id })} className="items-center" type="button" > Delete ); } export function TaggingRules() { const { data: prompts, isLoading } = api.prompts.list.useQuery(); return (
Tagging Rules

Prompts that you add here will be included as rules to the model during tag generation. You can view the final prompts in the prompt preview section.

{isLoading && } {prompts && prompts.length == 0 && (

You don't have any custom prompts yet.

)} {prompts && prompts.map((prompt) => )}
); } export function PromptDemo() { const { data: prompts } = api.prompts.list.useQuery(); const clientConfig = useClientConfig(); return (
Prompt Preview

Text Prompt

{buildTextPrompt( clientConfig.inference.inferredTagLang, (prompts ?? []) .filter((p) => p.appliesTo == "text" || p.appliesTo == "all") .map((p) => p.text), "\n\n", /* context length */ 1024 /* The value here doesn't matter */, ).trim()}

Image Prompt

{buildImagePrompt( clientConfig.inference.inferredTagLang, (prompts ?? []) .filter((p) => p.appliesTo == "images" || p.appliesTo == "all") .map((p) => p.text), ).trim()}
); } export default function AISettings() { return ( <>
AI Settings
); }