gptrans 1.1.8 → 1.2.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/db/gptrans_ar.json +0 -9
- package/db/gptrans_it.json +10 -0
- package/demo/case_2.js +7 -5
- package/index.js +47 -8
- package/isoAssoc.js +22 -16
- package/package.json +2 -1
package/db/gptrans_ar.json
CHANGED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"hello_name_1987p1n": "Ciao, {name}!",
|
|
3
|
+
"topup_uzdh5y": "Ricarica",
|
|
4
|
+
"transf_176pc1a": "Trasferimento",
|
|
5
|
+
"deposi_wg2ec5": "Deposito",
|
|
6
|
+
"balanc_1rv8if7": "Saldo",
|
|
7
|
+
"transa_1wtqm5d": "Transazione",
|
|
8
|
+
"accoun_x1y0v8": "Conto",
|
|
9
|
+
"card_yis1ox": "Carta"
|
|
10
|
+
}
|
package/demo/case_2.js
CHANGED
|
@@ -2,18 +2,20 @@ import GPTrans from '../index.js';
|
|
|
2
2
|
|
|
3
3
|
try {
|
|
4
4
|
const gptrans = new GPTrans({
|
|
5
|
-
target: '
|
|
6
|
-
model: '
|
|
5
|
+
target: 'it',
|
|
6
|
+
model: 'gpt-4o-mini',
|
|
7
7
|
});
|
|
8
8
|
|
|
9
|
+
await gptrans.preload();
|
|
10
|
+
console.log('ready');
|
|
11
|
+
|
|
9
12
|
console.log(gptrans.t('Top-up'));
|
|
10
13
|
console.log(gptrans.t('Transfer'));
|
|
11
14
|
console.log(gptrans.t('Deposit'));
|
|
12
15
|
console.log(gptrans.t('Balance'));
|
|
13
16
|
console.log(gptrans.t('Transaction'));
|
|
14
17
|
console.log(gptrans.t('Account'));
|
|
15
|
-
console.log(gptrans.t('Card'));
|
|
18
|
+
console.log(gptrans.t('Card'));
|
|
16
19
|
} catch (e) {
|
|
17
20
|
console.error(e);
|
|
18
|
-
}
|
|
19
|
-
|
|
21
|
+
}
|
package/index.js
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import DeepBase from 'deepbase';
|
|
2
2
|
import stringHash from 'string-hash';
|
|
3
3
|
import { ModelMix, MixOpenAI, MixAnthropic } from 'modelmix';
|
|
4
|
+
import { isoAssoc, isLanguageAvailable } from './isoAssoc.js';
|
|
4
5
|
import dotenv from 'dotenv';
|
|
5
|
-
import path from 'path';
|
|
6
6
|
|
|
7
|
-
import { isoAssoc } from './isoAssoc.js';
|
|
8
7
|
dotenv.config();
|
|
9
8
|
|
|
10
|
-
class
|
|
9
|
+
class GPTrans {
|
|
11
10
|
static #mmixInstance = null;
|
|
12
11
|
|
|
13
12
|
static get mmix() {
|
|
@@ -22,10 +21,14 @@ class Gptrans {
|
|
|
22
21
|
return this.#mmixInstance;
|
|
23
22
|
}
|
|
24
23
|
|
|
24
|
+
static isLanguageAvailable(langCode) {
|
|
25
|
+
return isLanguageAvailable(langCode);
|
|
26
|
+
}
|
|
27
|
+
|
|
25
28
|
constructor({ from = 'en-US', target = 'es-AR', model = 'claude-3-7-sonnet-20250219', batchThreshold = 1000, debounceTimeout = 500, promptFile = null, context = '' }) {
|
|
26
29
|
this.dbTarget = new DeepBase({ name: 'gptrans_' + target });
|
|
27
30
|
this.dbFrom = new DeepBase({ name: 'gptrans_from_' + from });
|
|
28
|
-
|
|
31
|
+
|
|
29
32
|
try {
|
|
30
33
|
this.replace_target = isoAssoc(target, 'TARGET_');
|
|
31
34
|
this.replace_from = isoAssoc(from, 'FROM_');
|
|
@@ -39,18 +42,19 @@ class Gptrans {
|
|
|
39
42
|
this.pendingCharCount = 0; // Add character count tracker
|
|
40
43
|
this.debounceTimer = null;
|
|
41
44
|
this.modelKey = model;
|
|
42
|
-
this.promptFile
|
|
45
|
+
this.promptFile = promptFile ?? new URL('./prompt/translate.md', import.meta.url).pathname;
|
|
43
46
|
this.context = context;
|
|
44
47
|
this.modelConfig = {
|
|
45
48
|
config: {
|
|
46
49
|
max_history: 1,
|
|
47
50
|
debug: false,
|
|
48
51
|
bottleneck: {
|
|
49
|
-
maxConcurrent:
|
|
52
|
+
maxConcurrent: 2,
|
|
50
53
|
}
|
|
51
54
|
},
|
|
52
55
|
options: { max_tokens: batchThreshold }
|
|
53
56
|
};
|
|
57
|
+
this.processing = false;
|
|
54
58
|
}
|
|
55
59
|
|
|
56
60
|
setContext(context = '') {
|
|
@@ -104,6 +108,8 @@ class Gptrans {
|
|
|
104
108
|
}
|
|
105
109
|
|
|
106
110
|
async _processBatch() {
|
|
111
|
+
this.processing = true;
|
|
112
|
+
|
|
107
113
|
const batch = Array.from(this.pendingTranslations.entries());
|
|
108
114
|
|
|
109
115
|
// Clear pending translations and character count before awaiting translation
|
|
@@ -119,10 +125,12 @@ class Gptrans {
|
|
|
119
125
|
batch.forEach(([key], index) => {
|
|
120
126
|
this.dbTarget.set(key, translatedTexts[index].trim());
|
|
121
127
|
});
|
|
128
|
+
|
|
129
|
+
this.processing = false;
|
|
122
130
|
}
|
|
123
131
|
|
|
124
132
|
async _translate(text) {
|
|
125
|
-
const model =
|
|
133
|
+
const model = GPTrans.mmix.create(this.modelKey, this.modelConfig);
|
|
126
134
|
|
|
127
135
|
model.setSystem("You are an expert translator specialized in literary translation between FROM_LANG and TARGET_DENONYM TARGET_LANG.");
|
|
128
136
|
|
|
@@ -154,6 +162,37 @@ class Gptrans {
|
|
|
154
162
|
key += stringHash(text + this.context).toString(36);
|
|
155
163
|
return key;
|
|
156
164
|
}
|
|
165
|
+
|
|
166
|
+
async preload({ target = this.replace_target.TARGET_ISO, model = this.modelKey, from = this.replace_from.FROM_ISO, batchThreshold = this.batchThreshold, debounceTimeout = this.debounceTimeout } = {}) {
|
|
167
|
+
|
|
168
|
+
// Create new GPTrans instance for the target language
|
|
169
|
+
const translator = new GPTrans({
|
|
170
|
+
from,
|
|
171
|
+
target,
|
|
172
|
+
model,
|
|
173
|
+
batchThreshold,
|
|
174
|
+
debounceTimeout,
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
// Process all entries in batches
|
|
178
|
+
for (const [key, text] of this.dbFrom.entries()) {
|
|
179
|
+
translator.get(key, text);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Wait for any pending translations to complete
|
|
183
|
+
if (translator.pendingTranslations.size > 0) {
|
|
184
|
+
await new Promise(resolve => {
|
|
185
|
+
const checkInterval = setInterval(() => {
|
|
186
|
+
if (translator.processing === false && translator.pendingTranslations.size === 0) {
|
|
187
|
+
clearInterval(checkInterval);
|
|
188
|
+
resolve();
|
|
189
|
+
}
|
|
190
|
+
}, 1000);
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return translator;
|
|
195
|
+
}
|
|
157
196
|
}
|
|
158
197
|
|
|
159
|
-
export default
|
|
198
|
+
export default GPTrans;
|
package/isoAssoc.js
CHANGED
|
@@ -152,38 +152,44 @@ const langName = {
|
|
|
152
152
|
'ms': 'Malay'
|
|
153
153
|
};
|
|
154
154
|
|
|
155
|
+
export function isLanguageAvailable(isoCode) {
|
|
156
|
+
if (!isoCode) return false;
|
|
157
|
+
|
|
158
|
+
const parts = isoCode.toLowerCase().split('-');
|
|
159
|
+
const lang = parts[0];
|
|
160
|
+
const country = parts.length > 1 ? parts[1] : null;
|
|
161
|
+
|
|
162
|
+
// Verificar si el idioma existe
|
|
163
|
+
if (!langName[lang]) return false;
|
|
164
|
+
|
|
165
|
+
// Si hay código de país, verificar si existe
|
|
166
|
+
if (country && !countryName[country]) return false;
|
|
167
|
+
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
|
|
155
171
|
export function isoAssoc(iso, prefix = '') {
|
|
156
172
|
if (!iso) {
|
|
157
173
|
throw new Error('ISO code is required');
|
|
158
174
|
}
|
|
175
|
+
|
|
176
|
+
// Usar la nueva función para validar el ISO
|
|
177
|
+
if (!isLanguageAvailable(iso)) {
|
|
178
|
+
throw new Error(`Invalid ISO code: ${iso}`);
|
|
179
|
+
}
|
|
159
180
|
|
|
160
181
|
const parts = iso.toLowerCase().split('-');
|
|
161
182
|
const lang = parts[0];
|
|
162
183
|
const country = parts.length > 1 ? parts[1] : null;
|
|
163
184
|
|
|
164
|
-
if (!langName[lang]) {
|
|
165
|
-
throw new Error(`Invalid language code: ${lang}`);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
if (country && !countryName[country]) {
|
|
169
|
-
throw new Error(`Invalid country code: ${country}`);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
// Special handling for languages with variants
|
|
173
185
|
let denonym = country ? countryDenonym[country] : 'Neutral';
|
|
174
|
-
|
|
175
|
-
// Handle Chinese without specified dialect (use "Simplified" instead of "Neutral")
|
|
186
|
+
|
|
176
187
|
if (lang === 'zh' && !country) {
|
|
177
188
|
denonym = 'Simplified';
|
|
178
189
|
}
|
|
179
|
-
// Handle Arabic without specified dialect (use "Standard" instead of "Neutral")
|
|
180
190
|
else if (lang === 'ar' && !country) {
|
|
181
191
|
denonym = 'Standard';
|
|
182
192
|
}
|
|
183
|
-
// Handle Portuguese without specified dialect (use "European" instead of "Neutral")
|
|
184
|
-
else if (lang === 'pt' && !country) {
|
|
185
|
-
denonym = 'European';
|
|
186
|
-
}
|
|
187
193
|
|
|
188
194
|
return {
|
|
189
195
|
[prefix + 'ISO']: iso,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gptrans",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.2.2",
|
|
5
5
|
"description": "🚆 GPTrans - The smarter AI-powered way to translate.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"translate",
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"language",
|
|
15
15
|
"translation",
|
|
16
16
|
"translator",
|
|
17
|
+
"magic",
|
|
17
18
|
"clasen"
|
|
18
19
|
],
|
|
19
20
|
"repository": {
|