feat(worker): --limit=N i translate-recipes för billig pilot över alla språk
- 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 <noreply@anthropic.com>
This commit is contained in:
@@ -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 # 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 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 # 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).
|
* 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() {
|
async function main() {
|
||||||
if (!process.env.DATABASE_URL) throw new Error("Sätt DATABASE_URL.");
|
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 =
|
const targets =
|
||||||
arg === "all" ? LANGS : arg.split(",").map((s) => s.trim()).filter(Boolean);
|
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) {
|
for (const l of targets) {
|
||||||
if (!LANGS.includes(l)) throw new Error(`Okänt språk: ${l}. Giltiga: ${LANGS.join(", ")}, all`);
|
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 queue = new Queue(JOB_QUEUE_NAME, { connection });
|
||||||
|
|
||||||
const recipes = await db
|
const baseQuery = db
|
||||||
.select({ id: schema.recipes.id })
|
.select({ id: schema.recipes.id, title: schema.recipes.titleSv })
|
||||||
.from(schema.recipes)
|
.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
|
const existing = await db
|
||||||
.select({ r: schema.recipeTranslations.recipeId, l: schema.recipeTranslations.languageTag })
|
.select({ r: schema.recipeTranslations.recipeId, l: schema.recipeTranslations.languageTag })
|
||||||
.from(schema.recipeTranslations);
|
.from(schema.recipeTranslations);
|
||||||
|
|||||||
Reference in New Issue
Block a user