@adminforth/i18n 2.3.0 → 2.3.2

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/build.log CHANGED
@@ -20,5 +20,5 @@ custom/package.json
20
20
  custom/pnpm-lock.yaml
21
21
  custom/tsconfig.json
22
22
 
23
- sent 47,968 bytes received 305 bytes 96,546.00 bytes/sec
24
- total size is 46,800 speedup is 0.97
23
+ sent 48,185 bytes received 305 bytes 96,980.00 bytes/sec
24
+ total size is 47,033 speedup is 0.97
@@ -82,6 +82,7 @@ const props = defineProps<{
82
82
  meta: any;
83
83
  getJobTasks: (limit?: number, offset?: number, fieldsToReturn?: string[]) => Promise<
84
84
  {state: Record<string, any>, status: string}[]>;
85
+ tasksStorageLost?: boolean;
85
86
  job: {
86
87
  id: string;
87
88
  name: string;
@@ -115,6 +116,11 @@ async function loadPage(targetPage: number) {
115
116
  } catch (error) {
116
117
  console.error('Failed to fetch translation tasks, retrying...', error);
117
118
  }
119
+ // the task storage of the job was deleted, tasks will never come back, so retrying only keeps the
120
+ // spinner on screen for nothing
121
+ if (props.tasksStorageLost) {
122
+ break;
123
+ }
118
124
  if (retry < retries - 1) {
119
125
  await new Promise(resolve => setTimeout(resolve, RETRY_DELAY_MS));
120
126
  }
@@ -82,6 +82,7 @@ const props = defineProps<{
82
82
  meta: any;
83
83
  getJobTasks: (limit?: number, offset?: number, fieldsToReturn?: string[]) => Promise<
84
84
  {state: Record<string, any>, status: string}[]>;
85
+ tasksStorageLost?: boolean;
85
86
  job: {
86
87
  id: string;
87
88
  name: string;
@@ -115,6 +116,11 @@ async function loadPage(targetPage: number) {
115
116
  } catch (error) {
116
117
  console.error('Failed to fetch translation tasks, retrying...', error);
117
118
  }
119
+ // the task storage of the job was deleted, tasks will never come back, so retrying only keeps the
120
+ // spinner on screen for nothing
121
+ if (props.tasksStorageLost) {
122
+ break;
123
+ }
118
124
  if (retry < retries - 1) {
119
125
  await new Promise(resolve => setTimeout(resolve, RETRY_DELAY_MS));
120
126
  }
package/dist/index.js CHANGED
@@ -586,10 +586,32 @@ export default class I18nPlugin extends AdminForthPlugin {
586
586
  const maxInputTokens = (_a = this.options.inputTokensPerBatch) !== null && _a !== void 0 ? _a : 30000;
587
587
  const limit = pLimit(30);
588
588
  const enStringsTokenLengthCache = {};
589
+ let tokenCountingFailed = false;
590
+ // Counting tokens is only used to split requests into batches. Some completion
591
+ // adapters cannot provide a token count, so use a conservative estimate instead
592
+ // of preventing the translation job from being created.
593
+ const getTokenLength = (value) => __awaiter(this, void 0, void 0, function* () {
594
+ try {
595
+ const tokenLength = yield this.options.completeAdapter.measureTokensCount(value);
596
+ if (!Number.isFinite(tokenLength) || tokenLength < 0) {
597
+ throw new Error(`Invalid token count: ${tokenLength}`);
598
+ }
599
+ return tokenLength;
600
+ }
601
+ catch (error) {
602
+ if (!tokenCountingFailed) {
603
+ tokenCountingFailed = true;
604
+ afLogger.warn(`Could not count tokens for translation batches in plugin ${this.constructor.name}; using a character-based estimate instead: ${String(error)}`);
605
+ }
606
+ // English text normally uses about 4 characters per token. Three gives
607
+ // batches some extra headroom for JSON formatting and unusual characters.
608
+ return Math.max(1, Math.ceil(value.length / 3));
609
+ }
610
+ });
589
611
  const tokenLengthPerString = (_a) => __awaiter(this, [_a], void 0, function* ({ str, id }) {
590
612
  const objectToPush = {
591
613
  en_string: str,
592
- numOfTokens: yield this.options.completeAdapter.measureTokensCount(`"${str}":"", \n`)
614
+ numOfTokens: yield getTokenLength(`"${str}":"", \n`)
593
615
  };
594
616
  enStringsTokenLengthCache[id] = objectToPush;
595
617
  });
@@ -622,7 +644,7 @@ export default class I18nPlugin extends AdminForthPlugin {
622
644
  \`\`\`
623
645
  `;
624
646
  const failedToTranslate = [];
625
- const basePromptTokenLength = yield this.options.completeAdapter.measureTokensCount(basePrompt);
647
+ const basePromptTokenLength = yield getTokenLength(basePrompt);
626
648
  const allowedTokensAmountForFields = maxInputTokens - basePromptTokenLength;
627
649
  const stringsToTranslate = Object.fromEntries(strings.map(s => [s.id, s]));
628
650
  const generationTasksInitialData = [];
package/index.ts CHANGED
@@ -698,12 +698,34 @@ export default class I18nPlugin extends AdminForthPlugin {
698
698
 
699
699
  const limit = pLimit(30);
700
700
  const enStringsTokenLengthCache: Record<string, any> = {};
701
+ let tokenCountingFailed = false;
702
+
703
+ // Counting tokens is only used to split requests into batches. Some completion
704
+ // adapters cannot provide a token count, so use a conservative estimate instead
705
+ // of preventing the translation job from being created.
706
+ const getTokenLength = async (value: string): Promise<number> => {
707
+ try {
708
+ const tokenLength = await this.options.completeAdapter.measureTokensCount(value);
709
+ if (!Number.isFinite(tokenLength) || tokenLength < 0) {
710
+ throw new Error(`Invalid token count: ${tokenLength}`);
711
+ }
712
+ return tokenLength;
713
+ } catch (error) {
714
+ if (!tokenCountingFailed) {
715
+ tokenCountingFailed = true;
716
+ afLogger.warn(`Could not count tokens for translation batches in plugin ${this.constructor.name}; using a character-based estimate instead: ${String(error)}`);
717
+ }
718
+ // English text normally uses about 4 characters per token. Three gives
719
+ // batches some extra headroom for JSON formatting and unusual characters.
720
+ return Math.max(1, Math.ceil(value.length / 3));
721
+ }
722
+ };
701
723
 
702
724
 
703
725
  const tokenLengthPerString = async ({ str, id }: { str: string; id: string }): Promise<void> => {
704
726
  const objectToPush = {
705
727
  en_string: str,
706
- numOfTokens: await this.options.completeAdapter.measureTokensCount(`"${str}":"", \n`)
728
+ numOfTokens: await getTokenLength(`"${str}":"", \n`)
707
729
  };
708
730
  enStringsTokenLengthCache[id] = objectToPush;
709
731
  }
@@ -741,7 +763,7 @@ export default class I18nPlugin extends AdminForthPlugin {
741
763
  `;
742
764
 
743
765
  const failedToTranslate: IFailedTranslation[] = [];
744
- const basePromptTokenLength = await this.options.completeAdapter.measureTokensCount(basePrompt);
766
+ const basePromptTokenLength = await getTokenLength(basePrompt);
745
767
  const allowedTokensAmountForFields = maxInputTokens - basePromptTokenLength;
746
768
  const stringsToTranslate: Record<string, { id: string; en_string: string; category: string }> = Object.fromEntries(strings.map(s => [s.id, s]));
747
769
  const generationTasksInitialData = []
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adminforth/i18n",
3
- "version": "2.3.0",
3
+ "version": "2.3.2",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",