From b5bfb7cb8b0787fde5f0cc218528a019e2dd293c Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 21 Aug 2026 15:42:51 +0000 Subject: [PATCH] =?UTF-8?q?feat(worker):=20--limit=3DN=20i=20translate-rec?= =?UTF-8?q?ipes=20f=C3=B6r=20billig=20pilot=20=C3=B6ver=20alla=20spr=C3=A5?= =?UTF-8?q?k?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - translate-recipes.ts får en valfri --limit=N som bara köar de N första (alfabetiskt) publicerade recepten × målspråk. Syfte: kvalitetskolla en handfull recept på ALLA språk innan hela svepet (~496 × 11) körs och betalas. - Skriver ut vilka recept som valts i pilot-läge så man vet vad man ska granska. - Oförändrat i övrigt: idempotent, resumbar, draft_ai -> verifiering -> publish-translations.ts publicerar bara det som klarat verifieringen. Co-Authored-By: Claude --- apps/worker/scripts/translate-recipes.ts | 25 ++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/apps/worker/scripts/translate-recipes.ts b/apps/worker/scripts/translate-recipes.ts index e703b62..12a103c 100644 --- a/apps/worker/scripts/translate-recipes.ts +++ b/apps/worker/scripts/translate-recipes.ts @@ -11,6 +11,7 @@ * pnpm --filter @app/worker exec tsx scripts/translate-recipes.ts es # bara spanska (testa först!) * pnpm --filter @app/worker exec tsx scripts/translate-recipes.ts es,de # flera * pnpm --filter @app/worker exec tsx scripts/translate-recipes.ts all # alla 11 språk + * pnpm --filter @app/worker exec tsx scripts/translate-recipes.ts all --limit=5 # PILOT: 5 recept × alla språk * * Kräver DATABASE_URL och REDIS_URL i miljön (samma som API/worker använder). */ @@ -37,9 +38,17 @@ const LANGS = ["en", "da", "de", "es", "fi", "fr", "it", "nb", "nl", "pl", "pt"] async function main() { if (!process.env.DATABASE_URL) throw new Error("Sätt DATABASE_URL."); - const arg = (process.argv[2] ?? "all").toLowerCase(); + const positional = process.argv.slice(2).filter((a) => !a.startsWith("--")); + const arg = (positional[0] ?? "all").toLowerCase(); const targets = arg === "all" ? LANGS : arg.split(",").map((s) => s.trim()).filter(Boolean); + // Valfri pilotgräns: --limit=N översätter bara de N första publicerade recepten + // (alfabetiskt) × målspråk – billig kvalitetskoll innan hela svepet. + const limitFlag = process.argv.find((a) => a.startsWith("--limit=")); + const limit = limitFlag ? Number(limitFlag.split("=")[1]) : null; + if (limitFlag && (!Number.isInteger(limit) || (limit ?? 0) <= 0)) { + throw new Error("--limit=N kräver ett positivt heltal, t.ex. --limit=5"); + } for (const l of targets) { if (!LANGS.includes(l)) throw new Error(`Okänt språk: ${l}. Giltiga: ${LANGS.join(", ")}, all`); } @@ -50,10 +59,18 @@ async function main() { }); const queue = new Queue(JOB_QUEUE_NAME, { connection }); - const recipes = await db - .select({ id: schema.recipes.id }) + const baseQuery = db + .select({ id: schema.recipes.id, title: schema.recipes.titleSv }) .from(schema.recipes) - .where(eq(schema.recipes.status, "published")); + .where(eq(schema.recipes.status, "published")) + .orderBy(schema.recipes.titleSv); + const recipes = limit ? await baseQuery.limit(limit) : await baseQuery; + if (limit) { + console.log( + `PILOT-läge: ${recipes.length} recept (alfabetiskt först) × ${targets.length} språk:`, + ); + for (const r of recipes) console.log(` • ${r.title}`); + } const existing = await db .select({ r: schema.recipeTranslations.recipeId, l: schema.recipeTranslations.languageTag }) .from(schema.recipeTranslations);