aboutsummaryrefslogtreecommitdiffstats
path: root/apps/web
diff options
context:
space:
mode:
Diffstat (limited to 'apps/web')
-rw-r--r--apps/web/components/settings/AISettings.tsx108
-rw-r--r--apps/web/lib/clientConfig.tsx2
-rw-r--r--apps/web/lib/i18n/locales/en/translation.json5
-rw-r--r--apps/web/lib/userSettings.tsx2
4 files changed, 117 insertions, 0 deletions
diff --git a/apps/web/components/settings/AISettings.tsx b/apps/web/components/settings/AISettings.tsx
index beaa93dc..d8adcb76 100644
--- a/apps/web/components/settings/AISettings.tsx
+++ b/apps/web/components/settings/AISettings.tsx
@@ -4,8 +4,10 @@ import { ActionButton } from "@/components/ui/action-button";
import {
Form,
FormControl,
+ FormDescription,
FormField,
FormItem,
+ FormLabel,
FormMessage,
} from "@/components/ui/form";
import { FullPageSpinner } from "@/components/ui/full-page-spinner";
@@ -18,15 +20,18 @@ import {
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
+import { Switch } from "@/components/ui/switch";
import { toast } from "@/components/ui/use-toast";
import { useClientConfig } from "@/lib/clientConfig";
import { useTranslation } from "@/lib/i18n/client";
import { api } from "@/lib/trpc";
+import { useUserSettings } from "@/lib/userSettings";
import { zodResolver } from "@hookform/resolvers/zod";
import { Plus, Save, Trash2 } from "lucide-react";
import { useForm } from "react-hook-form";
import { z } from "zod";
+import { useUpdateUserSettings } from "@karakeep/shared-react/hooks/users";
import {
buildImagePrompt,
buildSummaryPromptUntruncated,
@@ -37,6 +42,108 @@ import {
ZPrompt,
zUpdatePromptSchema,
} from "@karakeep/shared/types/prompts";
+import { zUpdateUserSettingsSchema } from "@karakeep/shared/types/users";
+
+export function AIPreferences() {
+ const { t } = useTranslation();
+ const clientConfig = useClientConfig();
+ const settings = useUserSettings();
+
+ const { mutate: updateSettings } = useUpdateUserSettings({
+ onSuccess: () => {
+ toast({
+ description: "Settings updated successfully!",
+ });
+ },
+ onError: () => {
+ toast({
+ description: "Failed to update settings",
+ variant: "destructive",
+ });
+ },
+ });
+
+ const form = useForm<z.infer<typeof zUpdateUserSettingsSchema>>({
+ resolver: zodResolver(zUpdateUserSettingsSchema),
+ values: settings
+ ? {
+ autoTaggingEnabled: settings.autoTaggingEnabled,
+ autoSummarizationEnabled: settings.autoSummarizationEnabled,
+ }
+ : undefined,
+ });
+
+ const showAutoTagging = clientConfig.inference.enableAutoTagging;
+ const showAutoSummarization = clientConfig.inference.enableAutoSummarization;
+
+ // Don't show the section if neither feature is enabled on the server
+ if (!showAutoTagging && !showAutoSummarization) {
+ return null;
+ }
+
+ return (
+ <div className="mt-2 flex flex-col gap-2">
+ <p className="mb-1 text-xs italic text-muted-foreground">
+ {t("settings.ai.ai_preferences_description")}
+ </p>
+ <Form {...form}>
+ <form className="space-y-4">
+ {showAutoTagging && (
+ <FormField
+ control={form.control}
+ name="autoTaggingEnabled"
+ render={({ field }) => (
+ <FormItem className="flex flex-row items-center justify-between rounded-lg border p-3">
+ <div className="space-y-0.5">
+ <FormLabel>{t("settings.ai.auto_tagging")}</FormLabel>
+ <FormDescription>
+ {t("settings.ai.auto_tagging_description")}
+ </FormDescription>
+ </div>
+ <FormControl>
+ <Switch
+ checked={field.value ?? true}
+ onCheckedChange={(checked) => {
+ field.onChange(checked);
+ updateSettings({ autoTaggingEnabled: checked });
+ }}
+ />
+ </FormControl>
+ </FormItem>
+ )}
+ />
+ )}
+
+ {showAutoSummarization && (
+ <FormField
+ control={form.control}
+ name="autoSummarizationEnabled"
+ render={({ field }) => (
+ <FormItem className="flex flex-row items-center justify-between rounded-lg border p-3">
+ <div className="space-y-0.5">
+ <FormLabel>{t("settings.ai.auto_summarization")}</FormLabel>
+ <FormDescription>
+ {t("settings.ai.auto_summarization_description")}
+ </FormDescription>
+ </div>
+ <FormControl>
+ <Switch
+ checked={field.value ?? true}
+ onCheckedChange={(checked) => {
+ field.onChange(checked);
+ updateSettings({ autoSummarizationEnabled: checked });
+ }}
+ />
+ </FormControl>
+ </FormItem>
+ )}
+ />
+ )}
+ </form>
+ </Form>
+ </div>
+ );
+}
export function PromptEditor() {
const { t } = useTranslation();
@@ -353,6 +460,7 @@ export default function AISettings() {
<div className="w-full text-2xl font-medium sm:w-1/3">
{t("settings.ai.ai_settings")}
</div>
+ <AIPreferences />
<TaggingRules />
</div>
</div>
diff --git a/apps/web/lib/clientConfig.tsx b/apps/web/lib/clientConfig.tsx
index 9331a7af..ab367be0 100644
--- a/apps/web/lib/clientConfig.tsx
+++ b/apps/web/lib/clientConfig.tsx
@@ -14,6 +14,8 @@ export const ClientConfigCtx = createContext<ClientConfig>({
inference: {
isConfigured: false,
inferredTagLang: "english",
+ enableAutoTagging: false,
+ enableAutoSummarization: false,
},
serverVersion: undefined,
disableNewReleaseCheck: true,
diff --git a/apps/web/lib/i18n/locales/en/translation.json b/apps/web/lib/i18n/locales/en/translation.json
index d05ca702..08dc33e4 100644
--- a/apps/web/lib/i18n/locales/en/translation.json
+++ b/apps/web/lib/i18n/locales/en/translation.json
@@ -222,6 +222,11 @@
},
"ai": {
"ai_settings": "AI Settings",
+ "ai_preferences_description": "Control which AI features are enabled for your account.",
+ "auto_tagging": "Auto-tagging",
+ "auto_tagging_description": "Automatically generate tags for your bookmarks using AI.",
+ "auto_summarization": "Auto-summarization",
+ "auto_summarization_description": "Automatically generate summaries for your bookmarks using AI.",
"tagging_rules": "Tagging Rules",
"tagging_rule_description": "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.",
"prompt_preview": "Prompt Preview",
diff --git a/apps/web/lib/userSettings.tsx b/apps/web/lib/userSettings.tsx
index 2bb7c8a5..d35c9e56 100644
--- a/apps/web/lib/userSettings.tsx
+++ b/apps/web/lib/userSettings.tsx
@@ -16,6 +16,8 @@ export const UserSettingsContext = createContext<ZUserSettings>({
readerFontSize: null,
readerLineHeight: null,
readerFontFamily: null,
+ autoTaggingEnabled: null,
+ autoSummarizationEnabled: null,
});
export function UserSettingsContextProvider({