gpt-po 1.2.1 → 1.2.4
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 +9 -2
- package/README_zh-CN.md +8 -1
- package/lib/package.json +1 -1
- package/lib/src/index.d.ts +1 -1
- package/lib/src/index.js +6 -4
- package/lib/src/translate.d.ts +3 -3
- package/lib/src/translate.js +24 -16
- package/lib/src/userprompt.txt +9 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -19,6 +19,11 @@ Set `OPENAI_API_KEY` before using this tool.
|
|
|
19
19
|
|
|
20
20
|
**It is recommended to use the paid OpenAI API to improve translation speed, as the free OpenAI API is slower (only 3 translations per minute) and has usage restrictions.**
|
|
21
21
|
|
|
22
|
+
### Environment Variables
|
|
23
|
+
- `OPENAI_API_KEY`: OpenAI API key.
|
|
24
|
+
- `OPENAI_API_HOST`: OpenAI API host (default: https://api.openai.com).
|
|
25
|
+
- `OPENAI_MODEL_TMP`: OpenAI model temperature (default: 0.1).
|
|
26
|
+
|
|
22
27
|
## Usage Scenarios
|
|
23
28
|
|
|
24
29
|
- `gpt-po sync --po <file> --pot <file>` Update the po file based on the pot file, while preserving the original translations.
|
|
@@ -60,7 +65,9 @@ Options:
|
|
|
60
65
|
--verbose show verbose log
|
|
61
66
|
-l, --lang <lang> target language (ISO 639-1 code)
|
|
62
67
|
-o, --output <file> output file path, overwirte po file by default
|
|
63
|
-
--context
|
|
68
|
+
--context <file> context file path (provides additional context to the bot)
|
|
69
|
+
--context-length <length> Maximum accumulated length of source strings (msgid) to translate in each API request (default: 2000, env: API_CONTEXT_LENGTH)
|
|
70
|
+
--timeout <ms> Timeout in milliseconds for API requests (default: 20000, env: API_TIMEOUT)
|
|
64
71
|
-h, --help display help for command
|
|
65
72
|
```
|
|
66
73
|
|
|
@@ -90,4 +97,4 @@ Options:
|
|
|
90
97
|
--po <file> po file path
|
|
91
98
|
--pot <file> pot file path
|
|
92
99
|
-h, --help display help for command
|
|
93
|
-
```
|
|
100
|
+
```
|
package/README_zh-CN.md
CHANGED
|
@@ -21,6 +21,11 @@ npm install gpt-po
|
|
|
21
21
|
|
|
22
22
|
*国内用户要设置`HTTPS_PROXY`环境变量上梯子才能用*
|
|
23
23
|
|
|
24
|
+
### 环境变量
|
|
25
|
+
- `OPENAI_API_KEY`: OpenAI API密钥。
|
|
26
|
+
- `OPENAI_API_HOST`: OpenAI API主机(默认:https://api.openai.com)。
|
|
27
|
+
- `OPENAI_MODEL_TMP`: OpenAI模型温度(默认:0.1)。
|
|
28
|
+
|
|
24
29
|
## 常见用法
|
|
25
30
|
|
|
26
31
|
- `gpt-po sync --po <file> --pot <file>` 根据 pot 文件更新 po 文件,同时保留原有翻译。
|
|
@@ -62,7 +67,9 @@ npm install gpt-po
|
|
|
62
67
|
--verbose 显示详细日志
|
|
63
68
|
-l, --lang <lang> 目标语言 (ISO 639-1 代码)
|
|
64
69
|
-o, --output <file> 输出文件路径,默认覆盖 po 文件
|
|
65
|
-
--context
|
|
70
|
+
--context <file> 上下文文件路径(为机器人提供额外的上下文)
|
|
71
|
+
--context-length <length> 每次 API 请求中源字符串(msgid)的最大累计长度(默认:2000,环境变量:API_CONTEXT_LENGTH)
|
|
72
|
+
--timeout <ms> API 请求超时时间(单位:毫秒,默认:20000,环境变量:API_TIMEOUT)
|
|
66
73
|
-h, --help 显示命令帮助
|
|
67
74
|
```
|
|
68
75
|
|
package/lib/package.json
CHANGED
package/lib/src/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
#!/usr/bin/env node --no-warnings=ExperimentalWarning
|
|
1
|
+
#!/usr/bin/env -S node --no-warnings=ExperimentalWarning
|
|
2
2
|
export {};
|
package/lib/src/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#!/usr/bin/env node --no-warnings=ExperimentalWarning
|
|
1
|
+
#!/usr/bin/env -S node --no-warnings=ExperimentalWarning
|
|
2
2
|
import { Command, Option } from "commander";
|
|
3
3
|
import path from "path";
|
|
4
4
|
import { fileURLToPath } from "url";
|
|
@@ -39,10 +39,12 @@ const translateCommand = new SharedOptionsCommand("translate")
|
|
|
39
39
|
.option("-l, --lang <lang>", "target language (ISO 639-1)")
|
|
40
40
|
.option("--verbose", "print verbose log")
|
|
41
41
|
.option("--context <file>", "text file that provides the bot additional context")
|
|
42
|
+
.addOption(new Option("--context-length <length>", "maximum accumulated length of source strings (msgid) to translate in each API request").env("API_CONTEXT_LENGTH").default("2000"))
|
|
43
|
+
.addOption(new Option("--timeout <ms>", "timeout in milliseconds for API requests").env("API_TIMEOUT").default("20000"))
|
|
42
44
|
.addOption(new Option("-o, --output <file>", "output file path, overwirte po file by default").conflicts("dir"))
|
|
43
45
|
.addCompileOptions()
|
|
44
46
|
.action(async (args) => {
|
|
45
|
-
const { key, host, model, po, dir, source, lang, verbose, output, context } = args;
|
|
47
|
+
const { key, host, model, po, dir, source, lang, verbose, output, context, contextLength, timeout } = args;
|
|
46
48
|
if (host) {
|
|
47
49
|
process.env.OPENAI_API_HOST = host;
|
|
48
50
|
}
|
|
@@ -57,10 +59,10 @@ const translateCommand = new SharedOptionsCommand("translate")
|
|
|
57
59
|
init();
|
|
58
60
|
const compileOptions = getCompileOptions(args);
|
|
59
61
|
if (po) {
|
|
60
|
-
await translatePo(model, po, source, lang, verbose, output, context, compileOptions);
|
|
62
|
+
await translatePo(model, po, source, lang, verbose, output, context, parseInt(contextLength), parseInt(timeout), compileOptions);
|
|
61
63
|
}
|
|
62
64
|
else if (dir) {
|
|
63
|
-
await translatePoDir(model, dir, source, lang, verbose, context, compileOptions);
|
|
65
|
+
await translatePoDir(model, dir, source, lang, verbose, context, parseInt(contextLength), parseInt(timeout), compileOptions);
|
|
64
66
|
}
|
|
65
67
|
else {
|
|
66
68
|
console.error("po file or directory is required");
|
package/lib/src/translate.d.ts
CHANGED
|
@@ -2,6 +2,6 @@ import { GetTextTranslation } from "gettext-parser";
|
|
|
2
2
|
import { OpenAI } from "openai";
|
|
3
3
|
import { CompileOptions } from "./utils.js";
|
|
4
4
|
export declare function init(force?: boolean): OpenAI;
|
|
5
|
-
export declare function translate(src: string, lang: string, model: string, translations: GetTextTranslation[], contextFile: string): Promise<void>;
|
|
6
|
-
export declare function translatePo(model: string, po: string, source: string, lang: string, verbose: boolean, output: string, contextFile: string, compileOptions?: CompileOptions): Promise<void>;
|
|
7
|
-
export declare function translatePoDir(model: string | undefined, dir: string, source: string, lang: string, verbose: boolean, contextFile: string, compileOptions?: CompileOptions): Promise<void>;
|
|
5
|
+
export declare function translate(src: string, lang: string, model: string, translations: GetTextTranslation[], contextFile: string, timeout: number): Promise<void>;
|
|
6
|
+
export declare function translatePo(model: string, po: string, source: string, lang: string, verbose: boolean, output: string, contextFile: string, contextLength: number, timeout: number, compileOptions?: CompileOptions): Promise<void>;
|
|
7
|
+
export declare function translatePoDir(model: string | undefined, dir: string, source: string, lang: string, verbose: boolean, contextFile: string, contextLength: number, timeout: number, compileOptions?: CompileOptions): Promise<void>;
|
package/lib/src/translate.js
CHANGED
|
@@ -36,7 +36,7 @@ export function init(force) {
|
|
|
36
36
|
}
|
|
37
37
|
return _openai;
|
|
38
38
|
}
|
|
39
|
-
export async function translate(src, lang, model, translations, contextFile) {
|
|
39
|
+
export async function translate(src, lang, model, translations, contextFile, timeout) {
|
|
40
40
|
const lang_code = lang
|
|
41
41
|
.toLowerCase()
|
|
42
42
|
.trim()
|
|
@@ -58,11 +58,14 @@ export async function translate(src, lang, model, translations, contextFile) {
|
|
|
58
58
|
.join("\n");
|
|
59
59
|
const context = contextFile ? "\n\nContext: " + fs.readFileSync(contextFile, "utf-8") : "";
|
|
60
60
|
const translationsContent = translations
|
|
61
|
-
.map((tr, idx) =>
|
|
61
|
+
.map((tr, idx) => {
|
|
62
|
+
const contextAttr = tr.msgctxt ? ` context="${tr.msgctxt}"` : "";
|
|
63
|
+
return `<translate index="${idx + dicts.user.length + 1}"${contextAttr}>${tr.msgid}</translate>`;
|
|
64
|
+
})
|
|
62
65
|
.join("\n");
|
|
63
66
|
const res = await _openai.chat.completions.create({
|
|
64
67
|
model: model,
|
|
65
|
-
temperature: 0.1,
|
|
68
|
+
temperature: process.env.OPENAI_MODEL_TMP ? parseFloat(process.env.OPENAI_MODEL_TMP) : 0.1,
|
|
66
69
|
messages: [
|
|
67
70
|
{
|
|
68
71
|
role: "system",
|
|
@@ -70,12 +73,12 @@ export async function translate(src, lang, model, translations, contextFile) {
|
|
|
70
73
|
},
|
|
71
74
|
{
|
|
72
75
|
role: "user",
|
|
73
|
-
content: `${_userprompt}\n\nWait for my incoming message in
|
|
76
|
+
content: `${_userprompt}\n\nWait for my incoming message(s) in \`${src}\` and translate them into \`${lang}\` (\`${src}\` and \`${lang}\` are XPG/POSIX locale names, used in Unix-like systems and GNU Gettext). ` +
|
|
74
77
|
notes
|
|
75
78
|
},
|
|
76
79
|
{
|
|
77
80
|
role: "assistant",
|
|
78
|
-
content: `Understood, I will translate your incoming
|
|
81
|
+
content: `Understood, I will translate your incoming \`${src}\` message(s) into \`${lang}\`, carefully following guidelines. Please go ahead and send your message(s) for translation.`
|
|
79
82
|
},
|
|
80
83
|
// add userdict
|
|
81
84
|
...(dicts.user.length > 0
|
|
@@ -91,7 +94,7 @@ export async function translate(src, lang, model, translations, contextFile) {
|
|
|
91
94
|
}
|
|
92
95
|
]
|
|
93
96
|
}, {
|
|
94
|
-
timeout
|
|
97
|
+
timeout,
|
|
95
98
|
stream: false
|
|
96
99
|
});
|
|
97
100
|
const content = res.choices[0].message.content ?? "";
|
|
@@ -107,7 +110,7 @@ export async function translate(src, lang, model, translations, contextFile) {
|
|
|
107
110
|
}
|
|
108
111
|
});
|
|
109
112
|
}
|
|
110
|
-
export async function translatePo(model, po, source, lang, verbose, output, contextFile, compileOptions) {
|
|
113
|
+
export async function translatePo(model, po, source, lang, verbose, output, contextFile, contextLength, timeout, compileOptions) {
|
|
111
114
|
const potrans = await parsePo(po);
|
|
112
115
|
if (!lang)
|
|
113
116
|
lang = potrans.headers["Language"];
|
|
@@ -132,11 +135,16 @@ export async function translatePo(model, po, source, lang, verbose, output, cont
|
|
|
132
135
|
let trimed = false;
|
|
133
136
|
for (const [ctx, entries] of Object.entries(potrans.translations)) {
|
|
134
137
|
for (const [msgid, trans] of Object.entries(entries)) {
|
|
135
|
-
if (msgid
|
|
138
|
+
if (msgid === "")
|
|
136
139
|
continue;
|
|
137
140
|
if (!trans.msgstr[0]) {
|
|
138
|
-
list.push(
|
|
139
|
-
|
|
141
|
+
list.push({
|
|
142
|
+
msgctxt: trans.msgctxt || ctx,
|
|
143
|
+
msgid,
|
|
144
|
+
msgid_plural: trans.msgid_plural,
|
|
145
|
+
msgstr: trans.msgstr,
|
|
146
|
+
comments: trans.comments
|
|
147
|
+
});
|
|
140
148
|
}
|
|
141
149
|
else if (trimRegx.test(trans.msgstr[0])) {
|
|
142
150
|
trimed = true;
|
|
@@ -162,13 +170,13 @@ export async function translatePo(model, po, source, lang, verbose, output, cont
|
|
|
162
170
|
await new Promise((resolve) => setTimeout(resolve, 20000));
|
|
163
171
|
}
|
|
164
172
|
const trans = list[i];
|
|
165
|
-
if (c <
|
|
173
|
+
if (c < contextLength) {
|
|
166
174
|
translations.push(trans);
|
|
167
175
|
c += trans.msgid.length;
|
|
168
176
|
}
|
|
169
|
-
if (c >=
|
|
177
|
+
if (c >= contextLength || i == list.length - 1) {
|
|
170
178
|
try {
|
|
171
|
-
await translate(source, lang, model, translations, contextFile);
|
|
179
|
+
await translate(source, lang, model, translations, contextFile, timeout);
|
|
172
180
|
if (verbose) {
|
|
173
181
|
translations.forEach((trans) => {
|
|
174
182
|
console.log(trans.msgid);
|
|
@@ -179,7 +187,7 @@ export async function translatePo(model, po, source, lang, verbose, output, cont
|
|
|
179
187
|
c = 0;
|
|
180
188
|
// update progress
|
|
181
189
|
printProgress(i + 1, list.length);
|
|
182
|
-
// save po file after each 2000 characters
|
|
190
|
+
// save po file after each 2000 characters by default
|
|
183
191
|
await compilePo(potrans, output || po, compileOptions);
|
|
184
192
|
}
|
|
185
193
|
catch (error) {
|
|
@@ -205,13 +213,13 @@ export async function translatePo(model, po, source, lang, verbose, output, cont
|
|
|
205
213
|
}
|
|
206
214
|
console.log("done.");
|
|
207
215
|
}
|
|
208
|
-
export async function translatePoDir(model = "gpt-3.5-turbo", dir, source, lang, verbose, contextFile, compileOptions) {
|
|
216
|
+
export async function translatePoDir(model = "gpt-3.5-turbo", dir, source, lang, verbose, contextFile, contextLength, timeout, compileOptions) {
|
|
209
217
|
const files = fs.readdirSync(dir);
|
|
210
218
|
for (const file of files) {
|
|
211
219
|
if (file.endsWith(".po")) {
|
|
212
220
|
const po = path.join(dir, file);
|
|
213
221
|
console.log(`translating ${po}`);
|
|
214
|
-
await translatePo(model, po, source, lang, verbose, po, contextFile, compileOptions);
|
|
222
|
+
await translatePo(model, po, source, lang, verbose, po, contextFile, contextLength, timeout, compileOptions);
|
|
215
223
|
}
|
|
216
224
|
}
|
|
217
225
|
}
|
package/lib/src/userprompt.txt
CHANGED
|
@@ -12,11 +12,18 @@ Translation guidelines are as follows:
|
|
|
12
12
|
- Input messages will be wrapped in `<translate>` XML tags with an index attribute, e.g., `<translate index="1">`.
|
|
13
13
|
- Respond with the translated message wrapped in `<translated>` XML tags, including the same index attribute, e.g., `<translated index="1">`.
|
|
14
14
|
|
|
15
|
-
4. **
|
|
15
|
+
4. **Context Handling**:
|
|
16
|
+
- Some messages will include a context attribute in the translate tag, e.g., `<translate index="1" context="Menu">`.
|
|
17
|
+
- Use this context to inform your translation but only return the translated text.
|
|
18
|
+
- Example (translating from `en_GB` to `fr_FR`):
|
|
19
|
+
Input: `<translate index="1" context="Menu">File</translate>`
|
|
20
|
+
Output: `<translated index="1">Fichier</translated>`
|
|
21
|
+
|
|
22
|
+
5. **Multiple Translations**:
|
|
16
23
|
- You may receive multiple translation requests in a single input, each with a unique index.
|
|
17
24
|
- Ensuring the complete number of requests are translated, even if they are repeated, while maintaining the original order when possible.
|
|
18
25
|
|
|
19
|
-
**
|
|
26
|
+
**Example (translating from `en_US` to `zh_CN`):**
|
|
20
27
|
- Input:
|
|
21
28
|
`<translate index="1">This is a message. </translate>`
|
|
22
29
|
`<translate index="2"> Hello %s</translate>`
|