gptrans 1.4.8 → 1.5.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/README.md +4 -3
- package/db/gptrans_en.json +9 -0
- package/demo/case_4.js +2 -2
- package/index.js +52 -34
- package/isoAssoc.js +6 -2
- package/package.json +1 -1
- package/prompt/translate.md +2 -0
package/README.md
CHANGED
|
@@ -65,11 +65,12 @@ When creating a new instance of GPTrans, you can customize:
|
|
|
65
65
|
|
|
66
66
|
| Option | Description | Default |
|
|
67
67
|
|--------|-------------|---------|
|
|
68
|
-
| `from` | Source language locale (BCP 47) | `
|
|
69
|
-
| `target` | Target language locale (BCP 47) | `
|
|
68
|
+
| `from` | Source language locale (BCP 47) | `en-US` |
|
|
69
|
+
| `target` | Target language locale (BCP 47) | `es` |
|
|
70
70
|
| `model` | Translation model key | `claude-3-7-sonnet` |
|
|
71
|
-
| `batchThreshold` | Maximum number of characters to accumulate before triggering batch processing | `
|
|
71
|
+
| `batchThreshold` | Maximum number of characters to accumulate before triggering batch processing | `1500` |
|
|
72
72
|
| `debounceTimeout` | Time in milliseconds to wait before processing translations | `500` |
|
|
73
|
+
| `freeze` | Freeze mode to prevent translations from being queued | `false` |
|
|
73
74
|
|
|
74
75
|
### BCP 47 Language Tags
|
|
75
76
|
|
package/demo/case_4.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import GPTrans from '../index.js';
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
// Case 2: Translate from Spanish
|
|
4
|
+
// Case 2: Translate from Spanish to English
|
|
5
5
|
const model = new GPTrans({
|
|
6
6
|
from: 'es',
|
|
7
|
-
target: '
|
|
7
|
+
target: 'en',
|
|
8
8
|
});
|
|
9
9
|
|
|
10
10
|
await model.preload();
|
package/index.js
CHANGED
|
@@ -9,7 +9,16 @@ class GPTrans {
|
|
|
9
9
|
|
|
10
10
|
static get mmix() {
|
|
11
11
|
if (!this.#mmixInstance) {
|
|
12
|
-
const mmix = new ModelMix(
|
|
12
|
+
const mmix = new ModelMix({
|
|
13
|
+
config: {
|
|
14
|
+
max_history: 1,
|
|
15
|
+
debug: false,
|
|
16
|
+
bottleneck: {
|
|
17
|
+
minTime: 15000,
|
|
18
|
+
maxConcurrent: 1
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
});
|
|
13
22
|
|
|
14
23
|
mmix.attach(new MixOpenAI());
|
|
15
24
|
mmix.attach(new MixAnthropic());
|
|
@@ -23,7 +32,7 @@ class GPTrans {
|
|
|
23
32
|
return isLanguageAvailable(langCode);
|
|
24
33
|
}
|
|
25
34
|
|
|
26
|
-
constructor({ from = 'en-US', target = 'es
|
|
35
|
+
constructor({ from = 'en-US', target = 'es', model = 'claude-3-7-sonnet-20250219', batchThreshold = 1500, debounceTimeout = 500, promptFile = null, context = '', freeze = false }) {
|
|
27
36
|
|
|
28
37
|
try {
|
|
29
38
|
dotenv.config();
|
|
@@ -49,14 +58,8 @@ class GPTrans {
|
|
|
49
58
|
this.modelKey = model;
|
|
50
59
|
this.promptFile = promptFile ?? new URL('./prompt/translate.md', import.meta.url).pathname;
|
|
51
60
|
this.context = context;
|
|
61
|
+
this.freeze = freeze;
|
|
52
62
|
this.modelConfig = {
|
|
53
|
-
config: {
|
|
54
|
-
max_history: 1,
|
|
55
|
-
debug: false,
|
|
56
|
-
bottleneck: {
|
|
57
|
-
maxConcurrent: 2,
|
|
58
|
-
}
|
|
59
|
-
},
|
|
60
63
|
options: {
|
|
61
64
|
max_tokens: batchThreshold,
|
|
62
65
|
temperature: 0
|
|
@@ -85,14 +88,25 @@ class GPTrans {
|
|
|
85
88
|
}
|
|
86
89
|
|
|
87
90
|
get(key, text) {
|
|
91
|
+
|
|
92
|
+
if (!text || !text.trim()) {
|
|
93
|
+
return text;
|
|
94
|
+
}
|
|
95
|
+
|
|
88
96
|
const contextHash = this._hash(this.context);
|
|
89
97
|
const translation = this.dbTarget.get(contextHash, key);
|
|
90
98
|
|
|
91
99
|
if (!translation) {
|
|
100
|
+
|
|
92
101
|
if (!this.dbFrom.get(this.context, key)) {
|
|
93
102
|
this.dbFrom.set(this.context, key, text);
|
|
94
103
|
}
|
|
95
104
|
|
|
105
|
+
if (this.freeze) {
|
|
106
|
+
console.log(`Freeze mode: [${key}] ${text}`);
|
|
107
|
+
return text;
|
|
108
|
+
}
|
|
109
|
+
|
|
96
110
|
// Skip translation if context is empty and languages are the same
|
|
97
111
|
if (!this.context && this.replaceFrom.FROM_ISO === this.replaceTarget.TARGET_ISO) {
|
|
98
112
|
return text;
|
|
@@ -129,7 +143,11 @@ class GPTrans {
|
|
|
129
143
|
|
|
130
144
|
// Clear pending translations and character count before awaiting translation
|
|
131
145
|
this.pendingTranslations.clear();
|
|
146
|
+
|
|
132
147
|
this.modelConfig.options.max_tokens = this.pendingCharCount + 1000;
|
|
148
|
+
const minTime = Math.floor((60000 / (8000 / this.pendingCharCount)) * 1.4);
|
|
149
|
+
GPTrans.mmix.limiter.updateSettings({ minTime });
|
|
150
|
+
|
|
133
151
|
this.pendingCharCount = 0;
|
|
134
152
|
|
|
135
153
|
const textsToTranslate = batch.map(([_, text]) => text).join('\n---\n');
|
|
@@ -139,6 +157,14 @@ class GPTrans {
|
|
|
139
157
|
|
|
140
158
|
const contextHash = this._hash(context);
|
|
141
159
|
batch.forEach(([key], index) => {
|
|
160
|
+
|
|
161
|
+
if (!translatedTexts[index]) {
|
|
162
|
+
console.log(translations);
|
|
163
|
+
console.error(`No translation found for ${key}`);
|
|
164
|
+
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
|
|
142
168
|
this.dbTarget.set(contextHash, key, translatedTexts[index].trim());
|
|
143
169
|
});
|
|
144
170
|
|
|
@@ -188,38 +214,30 @@ class GPTrans {
|
|
|
188
214
|
return stringHash(input).toString(36);
|
|
189
215
|
}
|
|
190
216
|
|
|
191
|
-
async preload(
|
|
192
|
-
|
|
193
|
-
// Create new GPTrans instance for the target language
|
|
194
|
-
const translator = new GPTrans({
|
|
195
|
-
from,
|
|
196
|
-
target,
|
|
197
|
-
model,
|
|
198
|
-
batchThreshold,
|
|
199
|
-
debounceTimeout,
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
// Process all entries in batches
|
|
217
|
+
async preload() {
|
|
203
218
|
for (const [context, pairs] of this.dbFrom.entries()) {
|
|
204
|
-
|
|
219
|
+
this.setContext(context);
|
|
205
220
|
for (const [key, text] of Object.entries(pairs)) {
|
|
206
|
-
|
|
221
|
+
this.get(key, text);
|
|
207
222
|
}
|
|
208
223
|
}
|
|
209
224
|
|
|
210
225
|
// Wait for any pending translations to complete
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
});
|
|
220
|
-
}
|
|
226
|
+
await new Promise(resolve => {
|
|
227
|
+
const checkInterval = setInterval(() => {
|
|
228
|
+
if (this.dbFrom.keys().length === this.dbTarget.keys().length) {
|
|
229
|
+
clearInterval(checkInterval);
|
|
230
|
+
resolve();
|
|
231
|
+
}
|
|
232
|
+
}, 100);
|
|
233
|
+
});
|
|
221
234
|
|
|
222
|
-
return
|
|
235
|
+
return this;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
setFreeze(freeze = true) {
|
|
239
|
+
this.freeze = freeze;
|
|
240
|
+
return this;
|
|
223
241
|
}
|
|
224
242
|
}
|
|
225
243
|
|
package/isoAssoc.js
CHANGED
|
@@ -180,10 +180,14 @@ export function isoAssoc(iso, prefix = '') {
|
|
|
180
180
|
|
|
181
181
|
const parts = iso.toLowerCase().split('-');
|
|
182
182
|
const lang = parts[0];
|
|
183
|
-
|
|
183
|
+
let country = parts.length > 1 ? parts[1] : null;
|
|
184
184
|
|
|
185
|
-
|
|
185
|
+
if (lang === 'en' && !country) {
|
|
186
|
+
country = 'us';
|
|
187
|
+
}
|
|
186
188
|
|
|
189
|
+
let denonym = country ? countryDenonym[country] : 'Neutral';
|
|
190
|
+
|
|
187
191
|
if (lang === 'zh' && !country) {
|
|
188
192
|
denonym = 'Simplified';
|
|
189
193
|
}
|
package/package.json
CHANGED