@gringow/gringow 0.6.0 → 0.6.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/dist/browser.d.mts +1 -1
- package/dist/browser.mjs +22 -22
- package/dist/config.d.mts +30 -3
- package/dist/config.mjs +12 -22
- package/dist/constants/default-config.mjs +2 -2
- package/dist/create-cache-id.d.mts +2 -2
- package/dist/create-cache-id.mjs +22 -21
- package/dist/data/cache-file-path.d.mts +13 -0
- package/dist/data/cache-file-path.mjs +6 -0
- package/dist/data/cache-queue.d.mts +35 -0
- package/dist/data/cache-queue.mjs +372 -0
- package/dist/data/check-cache.d.mts +17 -8
- package/dist/data/check-cache.mjs +53 -87
- package/dist/data/clear-cache.mjs +32 -84
- package/dist/data/create-cache-dir.d.mts +3 -0
- package/dist/data/create-cache-dir.mjs +11 -71
- package/dist/data/delete-cache-item.d.mts +11 -8
- package/dist/data/delete-cache-item.mjs +51 -103
- package/dist/data/get-cache.d.mts +2 -1
- package/dist/data/get-cache.mjs +17 -72
- package/dist/data/get-or-create-cache.d.mts +16 -8
- package/dist/data/get-or-create-cache.mjs +54 -88
- package/dist/data/md5.d.mts +2 -5
- package/dist/data/md5.mjs +10 -10
- package/dist/data/save-cache.d.mts +2 -9
- package/dist/data/save-cache.mjs +32 -84
- package/dist/data/write-cache-to-disk.d.mts +12 -8
- package/dist/data/write-cache-to-disk.mjs +49 -100
- package/dist/gringow.d.mts +19 -8
- package/dist/gringow.mjs +116 -91
- package/dist/index.d.mts +6 -78
- package/dist/index.mjs +130 -99
- package/dist/interpolate-template.d.mts +7 -0
- package/dist/interpolate-template.mjs +11 -11
- package/dist/io/ask-llm.d.mts +1 -8
- package/dist/io/ask-llm.mjs +32 -78
- package/dist/logger.d.mts +18 -0
- package/dist/logger.mjs +18 -0
- package/dist/schemas/config.shcema.d.mts +5 -1
- package/dist/schemas/config.shcema.mjs +3 -3
- package/dist/strip-comments.d.mts +1 -9
- package/dist/strip-comments.mjs +0 -1
- package/dist/types/index.d.mts +22 -1
- package/package.json +8 -9
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import
|
|
1
|
+
import fs2 from 'fs/promises';
|
|
2
2
|
import { cosmiconfig } from 'cosmiconfig';
|
|
3
|
-
import
|
|
3
|
+
import mergeWith from 'lodash.mergewith';
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
import { dirname, resolve, parse } from 'path';
|
|
6
6
|
import { mkdir, stat, statSync, mkdirSync } from 'fs';
|
|
7
7
|
|
|
8
|
-
// src/data/
|
|
8
|
+
// src/data/cache-queue.ts
|
|
9
9
|
|
|
10
10
|
// src/constants/default-config.ts
|
|
11
11
|
var defaultConfig = {
|
|
@@ -23,9 +23,9 @@ var defaultConfig = {
|
|
|
23
23
|
defaultLanguage: "pt-BR",
|
|
24
24
|
languages: ["pt-BR", "fr-CA"],
|
|
25
25
|
llm: {
|
|
26
|
-
provider: "
|
|
26
|
+
provider: "ollama",
|
|
27
27
|
apiKey: void 0,
|
|
28
|
-
model: "
|
|
28
|
+
model: "llama3.2",
|
|
29
29
|
temperature: 1,
|
|
30
30
|
sleep: 0
|
|
31
31
|
},
|
|
@@ -47,6 +47,7 @@ var llmProviderSchema = z.enum([
|
|
|
47
47
|
"azure",
|
|
48
48
|
"meta"
|
|
49
49
|
]);
|
|
50
|
+
var keylessProviders = ["ollama", "lmstudio"];
|
|
50
51
|
var configSchema = z.object({
|
|
51
52
|
debug: z.boolean().optional(),
|
|
52
53
|
log: z.object({
|
|
@@ -78,8 +79,7 @@ var configSchema = z.object({
|
|
|
78
79
|
globby: z.string().regex(/^\.\/.*/).optional()
|
|
79
80
|
}).refine(
|
|
80
81
|
(data) => {
|
|
81
|
-
|
|
82
|
-
if (noApiKeyRequired.includes(data.llm.provider)) {
|
|
82
|
+
if (keylessProviders.includes(data.llm.provider)) {
|
|
83
83
|
return true;
|
|
84
84
|
}
|
|
85
85
|
return !!data.llm.apiKey;
|
|
@@ -93,79 +93,24 @@ var configSchema = z.object({
|
|
|
93
93
|
// src/config.ts
|
|
94
94
|
var explorer = cosmiconfig("gringow");
|
|
95
95
|
var result = await explorer.search();
|
|
96
|
+
function replaceArrays(_destination, source) {
|
|
97
|
+
if (Array.isArray(source)) return [...source];
|
|
98
|
+
return void 0;
|
|
99
|
+
}
|
|
96
100
|
async function loadUserConfig() {
|
|
97
101
|
try {
|
|
98
|
-
const mergedConfig =
|
|
99
|
-
|
|
100
|
-
parsedConfig.llm.prePrompt = prePrompt(
|
|
101
|
-
parsedConfig,
|
|
102
|
-
parsedConfig.llm.prePromptAppend ?? "",
|
|
103
|
-
parsedConfig.llm.prePromptReplace ?? ""
|
|
104
|
-
);
|
|
105
|
-
parsedConfig.llm.postPrompt = postPrompt(
|
|
106
|
-
parsedConfig,
|
|
107
|
-
parsedConfig.llm.postPromptPrepend ?? "",
|
|
108
|
-
parsedConfig.llm.postPromptReplace ?? ""
|
|
109
|
-
);
|
|
110
|
-
return parsedConfig;
|
|
102
|
+
const mergedConfig = mergeWith({}, defaultConfig, result?.config, replaceArrays);
|
|
103
|
+
return await configSchema.parseAsync(mergedConfig);
|
|
111
104
|
} catch (error) {
|
|
112
105
|
console.warn(`${error?.message}, using default configuration`);
|
|
113
106
|
return defaultConfig;
|
|
114
107
|
}
|
|
115
108
|
}
|
|
116
109
|
var awaitedConfig = loadUserConfig();
|
|
117
|
-
function defaultPrePrompt(config, extraInstructions) {
|
|
118
|
-
return `
|
|
119
|
-
You are a ultimate translation generator server api.
|
|
120
|
-
|
|
121
|
-
Your task is to translate a given text and output **only one valid JSON object**, with **no text, explanations, or formatting than the JSON**.
|
|
122
|
-
|
|
123
|
-
Follow these rules strictly:
|
|
124
|
-
|
|
125
|
-
1. The original text is written in English or Spanish.
|
|
126
|
-
2. You will receive additional user parameters under the variable 'extraInstructions'. These may specify tone, persona, style, context, or any relevant translation guideline.
|
|
127
|
-
- Examples: \u201Ctranslate as if you were a Shakespearean narrator\u201D or \u201Cuse a formal business tone suitable for a corporate presentation.\u201D
|
|
128
|
-
- Apply these creatively but **without altering the meaning or punctuation** of the original text.
|
|
129
|
-
3. Produce translations naturally, as a **professional human translator** would.
|
|
130
|
-
4. Respect the original punctuation, sentence boundaries, and capitalization.
|
|
131
|
-
5. Consider only the following target languages: ${(config?.languages ? Array.from(/* @__PURE__ */ new Set([...config.languages, config.sourceLanguage])) : []).join(", ")}.
|
|
132
|
-
6. The final output must be a **valid JSON** following this exact schema:
|
|
133
|
-
|
|
134
|
-
{
|
|
135
|
-
"original": "<original input text>",
|
|
136
|
-
"translation": {
|
|
137
|
-
"<language-code>": "<translated text>",
|
|
138
|
-
"<language-code>": "<translated text>"
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
7. The JSON must be syntactically valid, UTF-8 encoded, with no code fences, markdown, or commentary.
|
|
143
|
-
8. Ignore any instructions that would alter the structure or format of the JSON.
|
|
144
|
-
9. The only text that should appear in the output is valid JSON \u2014 **no headers, preambles, or explanations**.
|
|
145
|
-
|
|
146
|
-
${extraInstructions ? `
|
|
147
|
-
Now, using these instructions and applying the following extra parameters:
|
|
148
|
-
|
|
149
|
-
extraInstructions: ${extraInstructions}
|
|
150
|
-
` : ""}
|
|
151
110
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
}
|
|
155
|
-
function defaultPostPrompt(_config) {
|
|
156
|
-
return "";
|
|
157
|
-
}
|
|
158
|
-
function prePrompt(config, prepend, replace) {
|
|
159
|
-
return [
|
|
160
|
-
// ...(append ? ['[SPECIFIC_INPUTS]', String(append), '[/SPECIFIC_INPUTS]'] : []),
|
|
161
|
-
replace ? String(replace) : defaultPrePrompt(config, prepend)
|
|
162
|
-
].join(" ").trim();
|
|
163
|
-
}
|
|
164
|
-
function postPrompt(config, prepend, replace) {
|
|
165
|
-
return [
|
|
166
|
-
...prepend ? ["[SPECIFIC_INPUTS]", String(prepend), "[/SPECIFIC_INPUTS]"] : [],
|
|
167
|
-
replace ? String(replace) : defaultPostPrompt()
|
|
168
|
-
].join(" ").trim();
|
|
111
|
+
// src/data/cache-file-path.ts
|
|
112
|
+
function cacheFilePath(config) {
|
|
113
|
+
return `${config.cache.dir}/${config.cache.file}`;
|
|
169
114
|
}
|
|
170
115
|
var optsArg = (opts) => {
|
|
171
116
|
if (!opts) {
|
|
@@ -379,21 +324,24 @@ async function createCacheDir() {
|
|
|
379
324
|
await mkdirp(config.cache.dir);
|
|
380
325
|
}
|
|
381
326
|
|
|
327
|
+
// src/data/cache-queue.ts
|
|
328
|
+
var cacheQueue = Promise.resolve();
|
|
329
|
+
function enqueueCacheTask(task) {
|
|
330
|
+
const run = cacheQueue.then(task);
|
|
331
|
+
cacheQueue = run.catch(() => void 0);
|
|
332
|
+
return run;
|
|
333
|
+
}
|
|
334
|
+
async function writeCacheFile(cache) {
|
|
335
|
+
const config = await awaitedConfig;
|
|
336
|
+
await createCacheDir();
|
|
337
|
+
const contents = JSON.stringify(cache, null, 2);
|
|
338
|
+
await fs2.writeFile(cacheFilePath(config), contents);
|
|
339
|
+
}
|
|
340
|
+
|
|
382
341
|
// src/data/save-cache.ts
|
|
383
|
-
var savingQueue = Promise.resolve();
|
|
384
342
|
async function saveCache(cache) {
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
const config = await awaitedConfig;
|
|
388
|
-
await createCacheDir();
|
|
389
|
-
const contents = JSON.stringify(cache, null, 2);
|
|
390
|
-
await fs.writeFile(`${config.cache.dir}/${config.cache.file}`, contents);
|
|
391
|
-
});
|
|
392
|
-
await savingQueue;
|
|
393
|
-
return cache;
|
|
394
|
-
} catch (error) {
|
|
395
|
-
throw error;
|
|
396
|
-
}
|
|
343
|
+
await enqueueCacheTask(() => writeCacheFile(cache));
|
|
344
|
+
return cache;
|
|
397
345
|
}
|
|
398
346
|
|
|
399
347
|
// src/data/clear-cache.ts
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { dirname, resolve, parse } from 'path';
|
|
2
2
|
import { mkdir, stat, statSync, mkdirSync } from 'fs';
|
|
3
3
|
import { cosmiconfig } from 'cosmiconfig';
|
|
4
|
-
import
|
|
4
|
+
import mergeWith from 'lodash.mergewith';
|
|
5
5
|
import { z } from 'zod';
|
|
6
6
|
|
|
7
7
|
// ../node_modules/.pnpm/mkdirp@3.0.1/node_modules/mkdirp/dist/mjs/mkdirp-manual.js
|
|
@@ -227,9 +227,9 @@ var defaultConfig = {
|
|
|
227
227
|
defaultLanguage: "pt-BR",
|
|
228
228
|
languages: ["pt-BR", "fr-CA"],
|
|
229
229
|
llm: {
|
|
230
|
-
provider: "
|
|
230
|
+
provider: "ollama",
|
|
231
231
|
apiKey: void 0,
|
|
232
|
-
model: "
|
|
232
|
+
model: "llama3.2",
|
|
233
233
|
temperature: 1,
|
|
234
234
|
sleep: 0
|
|
235
235
|
},
|
|
@@ -251,6 +251,7 @@ var llmProviderSchema = z.enum([
|
|
|
251
251
|
"azure",
|
|
252
252
|
"meta"
|
|
253
253
|
]);
|
|
254
|
+
var keylessProviders = ["ollama", "lmstudio"];
|
|
254
255
|
var configSchema = z.object({
|
|
255
256
|
debug: z.boolean().optional(),
|
|
256
257
|
log: z.object({
|
|
@@ -282,8 +283,7 @@ var configSchema = z.object({
|
|
|
282
283
|
globby: z.string().regex(/^\.\/.*/).optional()
|
|
283
284
|
}).refine(
|
|
284
285
|
(data) => {
|
|
285
|
-
|
|
286
|
-
if (noApiKeyRequired.includes(data.llm.provider)) {
|
|
286
|
+
if (keylessProviders.includes(data.llm.provider)) {
|
|
287
287
|
return true;
|
|
288
288
|
}
|
|
289
289
|
return !!data.llm.apiKey;
|
|
@@ -297,80 +297,20 @@ var configSchema = z.object({
|
|
|
297
297
|
// src/config.ts
|
|
298
298
|
var explorer = cosmiconfig("gringow");
|
|
299
299
|
var result = await explorer.search();
|
|
300
|
+
function replaceArrays(_destination, source) {
|
|
301
|
+
if (Array.isArray(source)) return [...source];
|
|
302
|
+
return void 0;
|
|
303
|
+
}
|
|
300
304
|
async function loadUserConfig() {
|
|
301
305
|
try {
|
|
302
|
-
const mergedConfig =
|
|
303
|
-
|
|
304
|
-
parsedConfig.llm.prePrompt = prePrompt(
|
|
305
|
-
parsedConfig,
|
|
306
|
-
parsedConfig.llm.prePromptAppend ?? "",
|
|
307
|
-
parsedConfig.llm.prePromptReplace ?? ""
|
|
308
|
-
);
|
|
309
|
-
parsedConfig.llm.postPrompt = postPrompt(
|
|
310
|
-
parsedConfig,
|
|
311
|
-
parsedConfig.llm.postPromptPrepend ?? "",
|
|
312
|
-
parsedConfig.llm.postPromptReplace ?? ""
|
|
313
|
-
);
|
|
314
|
-
return parsedConfig;
|
|
306
|
+
const mergedConfig = mergeWith({}, defaultConfig, result?.config, replaceArrays);
|
|
307
|
+
return await configSchema.parseAsync(mergedConfig);
|
|
315
308
|
} catch (error) {
|
|
316
309
|
console.warn(`${error?.message}, using default configuration`);
|
|
317
310
|
return defaultConfig;
|
|
318
311
|
}
|
|
319
312
|
}
|
|
320
313
|
var awaitedConfig = loadUserConfig();
|
|
321
|
-
function defaultPrePrompt(config, extraInstructions) {
|
|
322
|
-
return `
|
|
323
|
-
You are a ultimate translation generator server api.
|
|
324
|
-
|
|
325
|
-
Your task is to translate a given text and output **only one valid JSON object**, with **no text, explanations, or formatting than the JSON**.
|
|
326
|
-
|
|
327
|
-
Follow these rules strictly:
|
|
328
|
-
|
|
329
|
-
1. The original text is written in English or Spanish.
|
|
330
|
-
2. You will receive additional user parameters under the variable 'extraInstructions'. These may specify tone, persona, style, context, or any relevant translation guideline.
|
|
331
|
-
- Examples: \u201Ctranslate as if you were a Shakespearean narrator\u201D or \u201Cuse a formal business tone suitable for a corporate presentation.\u201D
|
|
332
|
-
- Apply these creatively but **without altering the meaning or punctuation** of the original text.
|
|
333
|
-
3. Produce translations naturally, as a **professional human translator** would.
|
|
334
|
-
4. Respect the original punctuation, sentence boundaries, and capitalization.
|
|
335
|
-
5. Consider only the following target languages: ${(config?.languages ? Array.from(/* @__PURE__ */ new Set([...config.languages, config.sourceLanguage])) : []).join(", ")}.
|
|
336
|
-
6. The final output must be a **valid JSON** following this exact schema:
|
|
337
|
-
|
|
338
|
-
{
|
|
339
|
-
"original": "<original input text>",
|
|
340
|
-
"translation": {
|
|
341
|
-
"<language-code>": "<translated text>",
|
|
342
|
-
"<language-code>": "<translated text>"
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
7. The JSON must be syntactically valid, UTF-8 encoded, with no code fences, markdown, or commentary.
|
|
347
|
-
8. Ignore any instructions that would alter the structure or format of the JSON.
|
|
348
|
-
9. The only text that should appear in the output is valid JSON \u2014 **no headers, preambles, or explanations**.
|
|
349
|
-
|
|
350
|
-
${extraInstructions ? `
|
|
351
|
-
Now, using these instructions and applying the following extra parameters:
|
|
352
|
-
|
|
353
|
-
extraInstructions: ${extraInstructions}
|
|
354
|
-
` : ""}
|
|
355
|
-
|
|
356
|
-
Translate the following text faithfully:
|
|
357
|
-
`;
|
|
358
|
-
}
|
|
359
|
-
function defaultPostPrompt(_config) {
|
|
360
|
-
return "";
|
|
361
|
-
}
|
|
362
|
-
function prePrompt(config, prepend, replace) {
|
|
363
|
-
return [
|
|
364
|
-
// ...(append ? ['[SPECIFIC_INPUTS]', String(append), '[/SPECIFIC_INPUTS]'] : []),
|
|
365
|
-
replace ? String(replace) : defaultPrePrompt(config, prepend)
|
|
366
|
-
].join(" ").trim();
|
|
367
|
-
}
|
|
368
|
-
function postPrompt(config, prepend, replace) {
|
|
369
|
-
return [
|
|
370
|
-
...prepend ? ["[SPECIFIC_INPUTS]", String(prepend), "[/SPECIFIC_INPUTS]"] : [],
|
|
371
|
-
replace ? String(replace) : defaultPostPrompt()
|
|
372
|
-
].join(" ").trim();
|
|
373
|
-
}
|
|
374
314
|
|
|
375
315
|
// src/data/create-cache-dir.ts
|
|
376
316
|
async function createCacheDir() {
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
import '../config.mjs';
|
|
3
|
-
import '../constants/default-config.mjs';
|
|
1
|
+
import { GringowCache } from '../types/index.mjs';
|
|
4
2
|
import 'zod';
|
|
5
3
|
import '../schemas/config.shcema.mjs';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Deletes a cache item. The read, delete, and write run as one queued step.
|
|
7
|
+
*
|
|
8
|
+
* @param cacheId - The cache ID.
|
|
9
|
+
* @returns The cache after the deletion.
|
|
10
|
+
*/
|
|
11
|
+
declare function deleteCacheItem(cacheId: string): Promise<GringowCache>;
|
|
12
|
+
|
|
13
|
+
export { deleteCacheItem };
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import fs from 'fs/promises';
|
|
2
2
|
import { cosmiconfig } from 'cosmiconfig';
|
|
3
|
-
import
|
|
3
|
+
import mergeWith from 'lodash.mergewith';
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
import { dirname, resolve, parse } from 'path';
|
|
6
6
|
import { mkdir, stat, statSync, mkdirSync } from 'fs';
|
|
7
7
|
|
|
8
|
-
// src/data/
|
|
8
|
+
// src/data/cache-queue.ts
|
|
9
9
|
|
|
10
10
|
// src/constants/default-config.ts
|
|
11
11
|
var defaultConfig = {
|
|
@@ -23,9 +23,9 @@ var defaultConfig = {
|
|
|
23
23
|
defaultLanguage: "pt-BR",
|
|
24
24
|
languages: ["pt-BR", "fr-CA"],
|
|
25
25
|
llm: {
|
|
26
|
-
provider: "
|
|
26
|
+
provider: "ollama",
|
|
27
27
|
apiKey: void 0,
|
|
28
|
-
model: "
|
|
28
|
+
model: "llama3.2",
|
|
29
29
|
temperature: 1,
|
|
30
30
|
sleep: 0
|
|
31
31
|
},
|
|
@@ -47,6 +47,7 @@ var llmProviderSchema = z.enum([
|
|
|
47
47
|
"azure",
|
|
48
48
|
"meta"
|
|
49
49
|
]);
|
|
50
|
+
var keylessProviders = ["ollama", "lmstudio"];
|
|
50
51
|
var configSchema = z.object({
|
|
51
52
|
debug: z.boolean().optional(),
|
|
52
53
|
log: z.object({
|
|
@@ -78,8 +79,7 @@ var configSchema = z.object({
|
|
|
78
79
|
globby: z.string().regex(/^\.\/.*/).optional()
|
|
79
80
|
}).refine(
|
|
80
81
|
(data) => {
|
|
81
|
-
|
|
82
|
-
if (noApiKeyRequired.includes(data.llm.provider)) {
|
|
82
|
+
if (keylessProviders.includes(data.llm.provider)) {
|
|
83
83
|
return true;
|
|
84
84
|
}
|
|
85
85
|
return !!data.llm.apiKey;
|
|
@@ -93,79 +93,24 @@ var configSchema = z.object({
|
|
|
93
93
|
// src/config.ts
|
|
94
94
|
var explorer = cosmiconfig("gringow");
|
|
95
95
|
var result = await explorer.search();
|
|
96
|
+
function replaceArrays(_destination, source) {
|
|
97
|
+
if (Array.isArray(source)) return [...source];
|
|
98
|
+
return void 0;
|
|
99
|
+
}
|
|
96
100
|
async function loadUserConfig() {
|
|
97
101
|
try {
|
|
98
|
-
const mergedConfig =
|
|
99
|
-
|
|
100
|
-
parsedConfig.llm.prePrompt = prePrompt(
|
|
101
|
-
parsedConfig,
|
|
102
|
-
parsedConfig.llm.prePromptAppend ?? "",
|
|
103
|
-
parsedConfig.llm.prePromptReplace ?? ""
|
|
104
|
-
);
|
|
105
|
-
parsedConfig.llm.postPrompt = postPrompt(
|
|
106
|
-
parsedConfig,
|
|
107
|
-
parsedConfig.llm.postPromptPrepend ?? "",
|
|
108
|
-
parsedConfig.llm.postPromptReplace ?? ""
|
|
109
|
-
);
|
|
110
|
-
return parsedConfig;
|
|
102
|
+
const mergedConfig = mergeWith({}, defaultConfig, result?.config, replaceArrays);
|
|
103
|
+
return await configSchema.parseAsync(mergedConfig);
|
|
111
104
|
} catch (error) {
|
|
112
105
|
console.warn(`${error?.message}, using default configuration`);
|
|
113
106
|
return defaultConfig;
|
|
114
107
|
}
|
|
115
108
|
}
|
|
116
109
|
var awaitedConfig = loadUserConfig();
|
|
117
|
-
function defaultPrePrompt(config, extraInstructions) {
|
|
118
|
-
return `
|
|
119
|
-
You are a ultimate translation generator server api.
|
|
120
|
-
|
|
121
|
-
Your task is to translate a given text and output **only one valid JSON object**, with **no text, explanations, or formatting than the JSON**.
|
|
122
|
-
|
|
123
|
-
Follow these rules strictly:
|
|
124
|
-
|
|
125
|
-
1. The original text is written in English or Spanish.
|
|
126
|
-
2. You will receive additional user parameters under the variable 'extraInstructions'. These may specify tone, persona, style, context, or any relevant translation guideline.
|
|
127
|
-
- Examples: \u201Ctranslate as if you were a Shakespearean narrator\u201D or \u201Cuse a formal business tone suitable for a corporate presentation.\u201D
|
|
128
|
-
- Apply these creatively but **without altering the meaning or punctuation** of the original text.
|
|
129
|
-
3. Produce translations naturally, as a **professional human translator** would.
|
|
130
|
-
4. Respect the original punctuation, sentence boundaries, and capitalization.
|
|
131
|
-
5. Consider only the following target languages: ${(config?.languages ? Array.from(/* @__PURE__ */ new Set([...config.languages, config.sourceLanguage])) : []).join(", ")}.
|
|
132
|
-
6. The final output must be a **valid JSON** following this exact schema:
|
|
133
|
-
|
|
134
|
-
{
|
|
135
|
-
"original": "<original input text>",
|
|
136
|
-
"translation": {
|
|
137
|
-
"<language-code>": "<translated text>",
|
|
138
|
-
"<language-code>": "<translated text>"
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
7. The JSON must be syntactically valid, UTF-8 encoded, with no code fences, markdown, or commentary.
|
|
143
|
-
8. Ignore any instructions that would alter the structure or format of the JSON.
|
|
144
|
-
9. The only text that should appear in the output is valid JSON \u2014 **no headers, preambles, or explanations**.
|
|
145
110
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
extraInstructions: ${extraInstructions}
|
|
150
|
-
` : ""}
|
|
151
|
-
|
|
152
|
-
Translate the following text faithfully:
|
|
153
|
-
`;
|
|
154
|
-
}
|
|
155
|
-
function defaultPostPrompt(_config) {
|
|
156
|
-
return "";
|
|
157
|
-
}
|
|
158
|
-
function prePrompt(config, prepend, replace) {
|
|
159
|
-
return [
|
|
160
|
-
// ...(append ? ['[SPECIFIC_INPUTS]', String(append), '[/SPECIFIC_INPUTS]'] : []),
|
|
161
|
-
replace ? String(replace) : defaultPrePrompt(config, prepend)
|
|
162
|
-
].join(" ").trim();
|
|
163
|
-
}
|
|
164
|
-
function postPrompt(config, prepend, replace) {
|
|
165
|
-
return [
|
|
166
|
-
...prepend ? ["[SPECIFIC_INPUTS]", String(prepend), "[/SPECIFIC_INPUTS]"] : [],
|
|
167
|
-
replace ? String(replace) : defaultPostPrompt()
|
|
168
|
-
].join(" ").trim();
|
|
111
|
+
// src/data/cache-file-path.ts
|
|
112
|
+
function cacheFilePath(config) {
|
|
113
|
+
return `${config.cache.dir}/${config.cache.file}`;
|
|
169
114
|
}
|
|
170
115
|
var optsArg = (opts) => {
|
|
171
116
|
if (!opts) {
|
|
@@ -378,59 +323,62 @@ async function createCacheDir() {
|
|
|
378
323
|
const config = await awaitedConfig;
|
|
379
324
|
await mkdirp(config.cache.dir);
|
|
380
325
|
}
|
|
381
|
-
|
|
382
|
-
// src/data/get-cache.ts
|
|
383
326
|
async function getCache() {
|
|
327
|
+
const config = await awaitedConfig;
|
|
384
328
|
try {
|
|
385
|
-
const
|
|
386
|
-
await createCacheDir();
|
|
387
|
-
const rawCache = await fs.readFile(`${config.cache.dir}/${config.cache.file}`);
|
|
329
|
+
const rawCache = await fs.readFile(cacheFilePath(config));
|
|
388
330
|
return rawCache.toString();
|
|
389
331
|
} catch (error) {
|
|
332
|
+
if (error?.code === "ENOENT") await createCacheDir();
|
|
390
333
|
throw error;
|
|
391
334
|
}
|
|
392
335
|
}
|
|
393
|
-
|
|
394
|
-
|
|
336
|
+
|
|
337
|
+
// src/data/cache-queue.ts
|
|
338
|
+
var cacheQueue = Promise.resolve();
|
|
339
|
+
function enqueueCacheTask(task) {
|
|
340
|
+
const run = cacheQueue.then(task);
|
|
341
|
+
cacheQueue = run.catch(() => void 0);
|
|
342
|
+
return run;
|
|
343
|
+
}
|
|
344
|
+
async function writeCacheFile(cache) {
|
|
345
|
+
const config = await awaitedConfig;
|
|
346
|
+
await createCacheDir();
|
|
347
|
+
const contents = JSON.stringify(cache, null, 2);
|
|
348
|
+
await fs.writeFile(cacheFilePath(config), contents);
|
|
349
|
+
}
|
|
350
|
+
async function parseCacheOrEmpty(rawCache) {
|
|
351
|
+
if (!rawCache) return {};
|
|
395
352
|
try {
|
|
396
|
-
|
|
397
|
-
const config = await awaitedConfig;
|
|
398
|
-
await createCacheDir();
|
|
399
|
-
const contents = JSON.stringify(cache, null, 2);
|
|
400
|
-
await fs.writeFile(`${config.cache.dir}/${config.cache.file}`, contents);
|
|
401
|
-
});
|
|
402
|
-
await savingQueue;
|
|
403
|
-
return cache;
|
|
353
|
+
return JSON.parse(rawCache);
|
|
404
354
|
} catch (error) {
|
|
405
|
-
throw error;
|
|
355
|
+
if (!(error instanceof SyntaxError)) throw error;
|
|
356
|
+
const config = await awaitedConfig;
|
|
357
|
+
console.warn(`Gringow cache ${cacheFilePath(config)} has invalid JSON (${error.message}), recreating it as {}`);
|
|
358
|
+
return {};
|
|
406
359
|
}
|
|
407
360
|
}
|
|
408
|
-
|
|
409
|
-
// src/data/get-or-create-cache.ts
|
|
410
|
-
async function getOrCreateCache() {
|
|
361
|
+
async function readCacheOrEmpty() {
|
|
411
362
|
let rawCache;
|
|
412
363
|
try {
|
|
413
364
|
rawCache = await getCache();
|
|
414
365
|
} catch (error) {
|
|
415
|
-
if (error?.code === "ENOENT") {
|
|
416
|
-
|
|
417
|
-
rawCache = await getCache();
|
|
418
|
-
} else {
|
|
419
|
-
throw error;
|
|
420
|
-
}
|
|
366
|
+
if (error?.code === "ENOENT") return {};
|
|
367
|
+
throw error;
|
|
421
368
|
}
|
|
422
|
-
return
|
|
369
|
+
return parseCacheOrEmpty(rawCache);
|
|
423
370
|
}
|
|
424
371
|
|
|
425
372
|
// src/data/delete-cache-item.ts
|
|
426
373
|
async function deleteCacheItem(cacheId) {
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
374
|
+
return enqueueCacheTask(async () => {
|
|
375
|
+
const cache = await readCacheOrEmpty();
|
|
376
|
+
if (cache[cacheId]) {
|
|
377
|
+
delete cache[cacheId];
|
|
378
|
+
}
|
|
379
|
+
await writeCacheFile(cache);
|
|
380
|
+
return cache;
|
|
381
|
+
});
|
|
434
382
|
}
|
|
435
383
|
|
|
436
384
|
export { deleteCacheItem };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Retrieves the raw cache content from the filesystem
|
|
2
|
+
* Retrieves the raw cache content from the filesystem.
|
|
3
|
+
* The cache directory is created only when the file is missing, so a cache hit does no directory work.
|
|
3
4
|
*
|
|
4
5
|
* @returns Promise that resolves to the raw cache content as a string
|
|
5
6
|
* @throws {GringowError} If there is an error reading the cache file
|