diff options
| author | Mohamed Bassem <me@mbassem.com> | 2026-02-09 00:09:10 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-02-09 00:09:10 +0000 |
| commit | 4186c4c64c68892248ce8671d9b8e67fc7f884a0 (patch) | |
| tree | 91bbbfc0bb47a966b9e340fdbe2a61b2e10ebd19 /packages/shared | |
| parent | 77b186c3a599297da0cf19e923c66607ad7d74e7 (diff) | |
| download | karakeep-4186c4c64c68892248ce8671d9b8e67fc7f884a0.tar.zst | |
feat(ai): Support restricting AI tags to a subset of existing tags (#2444)
* feat(ai): Support restricting AI tags to a subset of existing tags
Co-authored-by: Claude <noreply@anthropic.com>
Diffstat (limited to 'packages/shared')
| -rw-r--r-- | packages/shared/prompts.server.ts | 17 | ||||
| -rw-r--r-- | packages/shared/prompts.ts | 10 | ||||
| -rw-r--r-- | packages/shared/types/tags.ts | 1 | ||||
| -rw-r--r-- | packages/shared/types/users.ts | 2 | ||||
| -rw-r--r-- | packages/shared/utils/tag.ts | 7 |
5 files changed, 28 insertions, 9 deletions
diff --git a/packages/shared/prompts.server.ts b/packages/shared/prompts.server.ts index 3e2666de..c53f4190 100644 --- a/packages/shared/prompts.server.ts +++ b/packages/shared/prompts.server.ts @@ -49,6 +49,7 @@ export async function buildTextPrompt( content: string, contextLength: number, tagStyle: ZTagStyle, + curatedTags?: string[], ): Promise<string> { content = preprocessContent(content); const promptTemplate = constructTextTaggingPrompt( @@ -56,17 +57,18 @@ export async function buildTextPrompt( customPrompts, "", tagStyle, + curatedTags, ); const promptSize = await calculateNumTokens(promptTemplate); - const truncatedContent = await truncateContent( - content, - contextLength - promptSize, - ); + const available = Math.max(0, contextLength - promptSize); + const truncatedContent = + available === 0 ? "" : await truncateContent(content, available); return constructTextTaggingPrompt( lang, customPrompts, truncatedContent, tagStyle, + curatedTags, ); } @@ -79,9 +81,8 @@ export async function buildSummaryPrompt( content = preprocessContent(content); const promptTemplate = constructSummaryPrompt(lang, customPrompts, ""); const promptSize = await calculateNumTokens(promptTemplate); - const truncatedContent = await truncateContent( - content, - contextLength - promptSize, - ); + const available = Math.max(0, contextLength - promptSize); + const truncatedContent = + available === 0 ? "" : await truncateContent(content, available); return constructSummaryPrompt(lang, customPrompts, truncatedContent); } diff --git a/packages/shared/prompts.ts b/packages/shared/prompts.ts index e878a18b..6c5c02c4 100644 --- a/packages/shared/prompts.ts +++ b/packages/shared/prompts.ts @@ -1,5 +1,5 @@ import type { ZTagStyle } from "./types/users"; -import { getTagStylePrompt } from "./utils/tag"; +import { getCuratedTagsPrompt, getTagStylePrompt } from "./utils/tag"; /** * Remove duplicate whitespaces to avoid tokenization issues @@ -12,8 +12,10 @@ export function buildImagePrompt( lang: string, customPrompts: string[], tagStyle: ZTagStyle, + curatedTags?: string[], ) { const tagStyleInstruction = getTagStylePrompt(tagStyle); + const curatedInstruction = getCuratedTagsPrompt(curatedTags); return ` You are an expert whose responsibility is to help with automatic text tagging for a read-it-later/bookmarking app. @@ -23,6 +25,7 @@ Analyze the attached image and suggest relevant tags that describe its key theme - If the tag is not generic enough, don't include it. - Aim for 10-15 tags. - If there are no good tags, don't emit any. +${curatedInstruction} ${tagStyleInstruction} ${customPrompts && customPrompts.map((p) => `- ${p}`).join("\n")} You must respond in valid JSON with the key "tags" and the value is list of tags. Don't wrap the response in a markdown code.`; @@ -36,8 +39,10 @@ export function constructTextTaggingPrompt( customPrompts: string[], content: string, tagStyle: ZTagStyle, + curatedTags?: string[], ): string { const tagStyleInstruction = getTagStylePrompt(tagStyle); + const curatedInstruction = getCuratedTagsPrompt(curatedTags); return ` You are an expert whose responsibility is to help with automatic tagging for a read-it-later/bookmarking app. @@ -50,6 +55,7 @@ Analyze the TEXT_CONTENT below and suggest relevant tags that describe its key t - Boilerplate content (cookie consent, login walls, GDPR notices) - Aim for 3-5 tags. - If there are no good tags, leave the array empty. +${curatedInstruction} ${tagStyleInstruction} ${customPrompts && customPrompts.map((p) => `- ${p}`).join("\n")} @@ -83,12 +89,14 @@ export function buildTextPromptUntruncated( customPrompts: string[], content: string, tagStyle: ZTagStyle, + curatedTags?: string[], ): string { return constructTextTaggingPrompt( lang, customPrompts, preprocessContent(content), tagStyle, + curatedTags, ); } diff --git a/packages/shared/types/tags.ts b/packages/shared/types/tags.ts index 91ad1d96..7ce70477 100644 --- a/packages/shared/types/tags.ts +++ b/packages/shared/types/tags.ts @@ -47,6 +47,7 @@ export const zTagCursorSchema = z.object({ export const zTagListRequestSchema = z.object({ nameContains: z.string().optional(), + ids: z.array(z.string()).optional(), attachedBy: z.enum([...zAttachedByEnumSchema.options, "none"]).optional(), sortBy: z.enum(["name", "usage", "relevance"]).optional().default("usage"), cursor: zTagCursorSchema.nullish().default({ page: 0 }), diff --git a/packages/shared/types/users.ts b/packages/shared/types/users.ts index 35db0e98..df4697f0 100644 --- a/packages/shared/types/users.ts +++ b/packages/shared/types/users.ts @@ -202,6 +202,7 @@ export const zUserSettingsSchema = z.object({ autoTaggingEnabled: z.boolean().nullable(), autoSummarizationEnabled: z.boolean().nullable(), tagStyle: zTagStyleSchema, + curatedTagIds: z.array(z.string()).nullable(), inferredTagLang: z.string().nullable(), }); @@ -220,6 +221,7 @@ export const zUpdateUserSettingsSchema = zUserSettingsSchema.partial().pick({ autoTaggingEnabled: true, autoSummarizationEnabled: true, tagStyle: true, + curatedTagIds: true, inferredTagLang: true, }); diff --git a/packages/shared/utils/tag.ts b/packages/shared/utils/tag.ts index 4dc7c696..b69b817e 100644 --- a/packages/shared/utils/tag.ts +++ b/packages/shared/utils/tag.ts @@ -28,3 +28,10 @@ export function getTagStylePrompt(style: TagStyle): string { return ""; } } + +export function getCuratedTagsPrompt(curatedTags?: string[]): string { + if (curatedTags && curatedTags.length > 0) { + return `- ONLY use tags from this predefined list: [${curatedTags.join(", ")}]. Do not create any new tags outside this list. If no tags fit, don't emit any.`; + } + return ""; +} |
