From 5f870549ce689c4c35df6a322c931fe78c51d5ac Mon Sep 17 00:00:00 2001 From: Mohamed Bassem Date: Sun, 7 Sep 2025 10:43:48 +0000 Subject: fix: don't mark inferenace job as failed when there's no content. fixes #1666 --- apps/workers/workers/inference/summarize.ts | 8 ++++++++ apps/workers/workers/inference/tagging.ts | 31 ++++++++++++++++++++++------- 2 files changed, 32 insertions(+), 7 deletions(-) (limited to 'apps') diff --git a/apps/workers/workers/inference/summarize.ts b/apps/workers/workers/inference/summarize.ts index 8564ef15..02a7f4e0 100644 --- a/apps/workers/workers/inference/summarize.ts +++ b/apps/workers/workers/inference/summarize.ts @@ -65,6 +65,14 @@ export async function runSummarization( (await Bookmark.getBookmarkPlainTextContent(link, bookmarkData.userId)) ?? ""; + if (!link.description && !content) { + // No content to infer from; skip summarization + logger.info( + `[inference] No content found for link "${bookmarkId}". Skipping summary.`, + ); + return; + } + textToSummarize = ` Title: ${link.title ?? ""} Description: ${link.description ?? ""} diff --git a/apps/workers/workers/inference/tagging.ts b/apps/workers/workers/inference/tagging.ts index 6c862f76..5697e73a 100644 --- a/apps/workers/workers/inference/tagging.ts +++ b/apps/workers/workers/inference/tagging.ts @@ -3,7 +3,10 @@ import { DequeuedJob, EnqueueOptions } from "liteque"; import { buildImpersonatingTRPCClient } from "trpc"; import { z } from "zod"; -import type { InferenceClient } from "@karakeep/shared/inference"; +import type { + InferenceClient, + InferenceResponse, +} from "@karakeep/shared/inference"; import type { ZOpenAIRequest } from "@karakeep/shared/queues"; import { db } from "@karakeep/db"; import { @@ -75,7 +78,7 @@ function tagNormalizer(col: Column) { } async function buildPrompt( bookmark: NonNullable>>, -) { +): Promise { const prompts = await fetchCustomPrompts(bookmark.userId, "text"); if (bookmark.link) { let content = @@ -85,9 +88,11 @@ async function buildPrompt( )) ?? ""; if (!bookmark.link.description && !content) { - throw new Error( - `No content found for link "${bookmark.id}". Skipping ...`, + // No content to infer from; signal skip to avoid marking job as failed + logger.info( + `[inference] No content found for link "${bookmark.id}". Skipping tagging.`, ); + return null; } return buildTextPrompt( serverConfig.inference.inferredTagLang, @@ -221,7 +226,11 @@ async function inferTagsFromText( inferenceClient: InferenceClient, abortSignal: AbortSignal, ) { - return await inferenceClient.inferFromText(await buildPrompt(bookmark), { + const prompt = await buildPrompt(bookmark); + if (!prompt) { + return null; + } + return await inferenceClient.inferFromText(prompt, { schema: openAIResponseSchema, abortSignal, }); @@ -233,7 +242,7 @@ async function inferTags( inferenceClient: InferenceClient, abortSignal: AbortSignal, ) { - let response; + let response: InferenceResponse | null; if (bookmark.link || bookmark.text) { response = await inferTagsFromText(bookmark, inferenceClient, abortSignal); } else if (bookmark.asset) { @@ -262,7 +271,8 @@ async function inferTags( } if (!response) { - throw new Error(`[inference][${jobId}] Inference response is empty`); + // Skipped due to missing content or prompt; propagate skip + return null; } try { @@ -432,6 +442,13 @@ export async function runTagging( job.abortSignal, ); + if (tags === null) { + logger.info( + `[inference][${jobId}] Skipping tagging for bookmark "${bookmark.id}" due to missing content.`, + ); + return; + } + await connectTags(bookmarkId, tags, bookmark.userId); // Propagate priority to child jobs -- cgit v1.2.3-70-g09d2