scribe-cms 0.0.14 → 0.0.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.cjs +162 -9
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +162 -9
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/translate-progress.d.ts.map +1 -1
- package/dist/index.cjs +134 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +134 -5
- package/dist/index.js.map +1 -1
- package/dist/src/translate/page-translator.d.ts +28 -0
- package/dist/src/translate/page-translator.d.ts.map +1 -1
- package/dist/src/translate/prompts/translation-prompt.d.ts +4 -6
- package/dist/src/translate/prompts/translation-prompt.d.ts.map +1 -1
- package/dist/src/translate/translate-core.d.ts +9 -0
- package/dist/src/translate/translate-core.d.ts.map +1 -1
- package/dist/src/translate/worklist.d.ts +6 -0
- package/dist/src/translate/worklist.d.ts.map +1 -1
- package/dist/studio/server.cjs.map +1 -1
- package/dist/studio/server.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"translate-progress.d.ts","sourceRoot":"","sources":["../../cli/translate-progress.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,sBAAsB,EAEvB,MAAM,qCAAqC,CAAC;
|
|
1
|
+
{"version":3,"file":"translate-progress.d.ts","sourceRoot":"","sources":["../../cli/translate-progress.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,sBAAsB,EAEvB,MAAM,qCAAqC,CAAC;AA4G7C,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,CAAC,KAAK,EAAE,sBAAsB,KAAK,IAAI,CAAC;IACjD,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB;AAED,wBAAgB,+BAA+B,CAAC,OAAO,GAAE;IACvD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,yBAAyB,CA8SjC"}
|
package/dist/index.cjs
CHANGED
|
@@ -2833,6 +2833,13 @@ function defaultLocalizationPrompt(localeName, locale) {
|
|
|
2833
2833
|
"Write as if a native speaker authored it for the target market."
|
|
2834
2834
|
].join(" ");
|
|
2835
2835
|
}
|
|
2836
|
+
function buildLocalizationPrompt(promptOverride, localeName, locale) {
|
|
2837
|
+
const localeDirective = defaultLocalizationPrompt(localeName, locale);
|
|
2838
|
+
if (!promptOverride) return localeDirective;
|
|
2839
|
+
return `${promptOverride}
|
|
2840
|
+
|
|
2841
|
+
${localeDirective}`;
|
|
2842
|
+
}
|
|
2836
2843
|
var TASK_FRAMING = "You are localizing the content below into a target language specified at the end of this prompt.";
|
|
2837
2844
|
function buildOutputFormatLine(hasFrontmatter, slugStrategy) {
|
|
2838
2845
|
if (!hasFrontmatter) {
|
|
@@ -2840,9 +2847,20 @@ function buildOutputFormatLine(hasFrontmatter, slugStrategy) {
|
|
|
2840
2847
|
}
|
|
2841
2848
|
return slugStrategy === "localized" ? "`frontmatter` (object with translated frontmatter fields), `body` (string, full MDX body), `slug` (string)." : "`frontmatter` (object), `body` (string).";
|
|
2842
2849
|
}
|
|
2850
|
+
function buildRetryContextSection(previousError) {
|
|
2851
|
+
return [
|
|
2852
|
+
"",
|
|
2853
|
+
"## Previous attempt",
|
|
2854
|
+
`A previous attempt at this translation was rejected with the following validation errors: ${previousError}. Produce a corrected translation that fixes these issues while re-checking every schema constraint (required fields, array minimums, maximum lengths).`
|
|
2855
|
+
];
|
|
2856
|
+
}
|
|
2843
2857
|
function buildPageTranslationPrompt(input) {
|
|
2844
2858
|
const localeName = LOCALE_NAMES[input.targetLocale] ?? input.targetLocale;
|
|
2845
|
-
const localizationPrompt =
|
|
2859
|
+
const localizationPrompt = buildLocalizationPrompt(
|
|
2860
|
+
input.resolved.promptOverride,
|
|
2861
|
+
localeName,
|
|
2862
|
+
input.targetLocale
|
|
2863
|
+
);
|
|
2846
2864
|
const prefix = [
|
|
2847
2865
|
TASK_FRAMING,
|
|
2848
2866
|
"",
|
|
@@ -2870,7 +2888,10 @@ function buildPageTranslationPrompt(input) {
|
|
|
2870
2888
|
buildOutputFormatLine(
|
|
2871
2889
|
Object.keys(input.translatableFrontmatter).length > 0,
|
|
2872
2890
|
input.slugStrategy
|
|
2873
|
-
)
|
|
2891
|
+
),
|
|
2892
|
+
// Retry context is locale-specific suffix material: it MUST stay after the
|
|
2893
|
+
// EN body so the cacheable prefix is byte-identical with and without it.
|
|
2894
|
+
...input.previousError ? buildRetryContextSection(input.previousError) : []
|
|
2874
2895
|
];
|
|
2875
2896
|
return [...prefix, ...suffix].join("\n");
|
|
2876
2897
|
}
|
|
@@ -3085,7 +3106,8 @@ function prepareTranslation(config, item, options, startedAt) {
|
|
|
3085
3106
|
contextLabel: resolveContextLabel(enDoc, item.enSlug),
|
|
3086
3107
|
translatableFrontmatter: payload.frontmatter,
|
|
3087
3108
|
enBody: payload.body,
|
|
3088
|
-
slugStrategy: type.slugStrategy
|
|
3109
|
+
slugStrategy: type.slugStrategy,
|
|
3110
|
+
previousError: item.previousError
|
|
3089
3111
|
});
|
|
3090
3112
|
const responseSchema = buildGeminiResponseSchema(type.schema, type.slugStrategy);
|
|
3091
3113
|
return {
|
|
@@ -3497,6 +3519,82 @@ async function runPool(items, concurrency, worker) {
|
|
|
3497
3519
|
function labelForItem(item) {
|
|
3498
3520
|
return `${item.contentType}/${item.enSlug}@${item.locale}`;
|
|
3499
3521
|
}
|
|
3522
|
+
function buildRetryWorklist(failed, originalByKey) {
|
|
3523
|
+
return failed.map((result) => {
|
|
3524
|
+
const key = translationItemKey(result);
|
|
3525
|
+
const original = originalByKey.get(key);
|
|
3526
|
+
return {
|
|
3527
|
+
contentType: result.contentType,
|
|
3528
|
+
enSlug: result.enSlug,
|
|
3529
|
+
locale: result.locale,
|
|
3530
|
+
reason: original?.reason ?? "missing",
|
|
3531
|
+
currentEnHash: original?.currentEnHash ?? "",
|
|
3532
|
+
storedEnHash: original?.storedEnHash,
|
|
3533
|
+
previousError: result.error ?? "Translation failed"
|
|
3534
|
+
};
|
|
3535
|
+
});
|
|
3536
|
+
}
|
|
3537
|
+
async function runRetryRound(config, retryItems, options) {
|
|
3538
|
+
const startedAt = Date.now();
|
|
3539
|
+
const translateOne = options.translateOne ?? ((item) => translatePage(config, item, { model: options.model, force: true }));
|
|
3540
|
+
if (options.mode === "direct") {
|
|
3541
|
+
const active = /* @__PURE__ */ new Set();
|
|
3542
|
+
await runPool(retryItems, options.concurrency, async (item) => {
|
|
3543
|
+
const label = labelForItem(item);
|
|
3544
|
+
active.add(label);
|
|
3545
|
+
options.onProgress?.({ type: "item-start", item, active: [...active] });
|
|
3546
|
+
const result = await translateOne(item);
|
|
3547
|
+
active.delete(label);
|
|
3548
|
+
options.onResult(result);
|
|
3549
|
+
});
|
|
3550
|
+
return;
|
|
3551
|
+
}
|
|
3552
|
+
const entries = [];
|
|
3553
|
+
for (const item of retryItems) {
|
|
3554
|
+
const itemStartedAt = Date.now();
|
|
3555
|
+
try {
|
|
3556
|
+
const outcome = prepareTranslation(config, item, { model: options.model, force: true }, itemStartedAt);
|
|
3557
|
+
if (outcome.status === "done") {
|
|
3558
|
+
options.onResult(outcome.result);
|
|
3559
|
+
} else {
|
|
3560
|
+
entries.push({
|
|
3561
|
+
apiModel: resolveGeminiModelId(displayModelFor(outcome.prepared)),
|
|
3562
|
+
prompt: outcome.prepared.prompt,
|
|
3563
|
+
prepared: outcome.prepared
|
|
3564
|
+
});
|
|
3565
|
+
}
|
|
3566
|
+
} catch (error) {
|
|
3567
|
+
options.onResult(failedResultForItem(item, error, itemStartedAt));
|
|
3568
|
+
}
|
|
3569
|
+
}
|
|
3570
|
+
const plans = planBatchJobs(entries);
|
|
3571
|
+
const submitted = await Promise.all(
|
|
3572
|
+
plans.map(async (plan, planIndex) => {
|
|
3573
|
+
try {
|
|
3574
|
+
return await submitBatchJobPlan(config, {
|
|
3575
|
+
plan,
|
|
3576
|
+
displayModel: normalizeGeminiDisplayName(plan.apiModel),
|
|
3577
|
+
jobIndex: planIndex,
|
|
3578
|
+
jobCount: plans.length,
|
|
3579
|
+
onProgress: options.onProgress
|
|
3580
|
+
});
|
|
3581
|
+
} catch (error) {
|
|
3582
|
+
for (const entry of plan.entries) {
|
|
3583
|
+
options.onResult(failedResultForItem(entry.prepared.item, error, startedAt));
|
|
3584
|
+
}
|
|
3585
|
+
return void 0;
|
|
3586
|
+
}
|
|
3587
|
+
})
|
|
3588
|
+
);
|
|
3589
|
+
const jobsToPoll = submitted.filter((row) => row !== void 0);
|
|
3590
|
+
if (jobsToPoll.length > 0) {
|
|
3591
|
+
await pollAndIngestBatchJobs(config, jobsToPoll, {
|
|
3592
|
+
jobCount: jobsToPoll.length,
|
|
3593
|
+
onProgress: options.onProgress,
|
|
3594
|
+
onResult: options.onResult
|
|
3595
|
+
});
|
|
3596
|
+
}
|
|
3597
|
+
}
|
|
3500
3598
|
async function translatePage(config, item, options = {}) {
|
|
3501
3599
|
const startedAt = Date.now();
|
|
3502
3600
|
let outcome;
|
|
@@ -3669,9 +3767,40 @@ async function translateWorklist(config, items, options = {}) {
|
|
|
3669
3767
|
});
|
|
3670
3768
|
}
|
|
3671
3769
|
}
|
|
3672
|
-
const
|
|
3770
|
+
const mainResults = collector.assemble();
|
|
3771
|
+
const failed = mainResults.filter((result) => result.failed);
|
|
3772
|
+
if (failed.length === 0) {
|
|
3773
|
+
const totals2 = summarizeResults(mainResults, Date.now() - startedAt);
|
|
3774
|
+
options.onProgress?.({ type: "done", results: mainResults, totals: totals2 });
|
|
3775
|
+
return mainResults;
|
|
3776
|
+
}
|
|
3777
|
+
options.onProgress?.({ type: "retry-start", failed });
|
|
3778
|
+
const originalByKey = new Map(
|
|
3779
|
+
items.map((item) => [translationItemKey(item), item])
|
|
3780
|
+
);
|
|
3781
|
+
const retryItems = buildRetryWorklist(failed, originalByKey);
|
|
3782
|
+
const retryByKey = /* @__PURE__ */ new Map();
|
|
3783
|
+
await runRetryRound(config, retryItems, {
|
|
3784
|
+
model: options.model,
|
|
3785
|
+
force: options.force,
|
|
3786
|
+
concurrency,
|
|
3787
|
+
mode,
|
|
3788
|
+
onProgress: options.onProgress,
|
|
3789
|
+
onResult: (result) => {
|
|
3790
|
+
retryByKey.set(translationItemKey(result), result);
|
|
3791
|
+
options.onProgress?.({ type: "item-done", result });
|
|
3792
|
+
}
|
|
3793
|
+
});
|
|
3794
|
+
const results = mainResults.map((result) => {
|
|
3795
|
+
if (!result.failed) return result;
|
|
3796
|
+
return retryByKey.get(translationItemKey(result)) ?? result;
|
|
3797
|
+
});
|
|
3798
|
+
const retriedTranslated = failed.filter((original) => {
|
|
3799
|
+
const retried = retryByKey.get(translationItemKey(original));
|
|
3800
|
+
return retried !== void 0 && !retried.failed && !retried.skipped;
|
|
3801
|
+
}).length;
|
|
3673
3802
|
const totals = summarizeResults(results, Date.now() - startedAt);
|
|
3674
|
-
options.onProgress?.({ type: "done", results, totals });
|
|
3803
|
+
options.onProgress?.({ type: "done", results, totals, retriedTranslated });
|
|
3675
3804
|
return results;
|
|
3676
3805
|
}
|
|
3677
3806
|
function countPendingItems(config, jobs) {
|