@gringow/gringow 0.6.1 → 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 +7 -8
package/dist/io/ask-llm.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { igniteEngine, Message } from 'multi-llm-ts';
|
|
2
|
-
import { cosmiconfig } from 'cosmiconfig';
|
|
3
|
-
import merge from 'lodash.merge';
|
|
4
2
|
import { z } from 'zod';
|
|
3
|
+
import { cosmiconfig } from 'cosmiconfig';
|
|
4
|
+
import mergeWith from 'lodash.mergewith';
|
|
5
5
|
|
|
6
6
|
// src/io/ask-llm.ts
|
|
7
7
|
|
|
@@ -21,9 +21,9 @@ var defaultConfig = {
|
|
|
21
21
|
defaultLanguage: "pt-BR",
|
|
22
22
|
languages: ["pt-BR", "fr-CA"],
|
|
23
23
|
llm: {
|
|
24
|
-
provider: "
|
|
24
|
+
provider: "ollama",
|
|
25
25
|
apiKey: void 0,
|
|
26
|
-
model: "
|
|
26
|
+
model: "llama3.2",
|
|
27
27
|
temperature: 1,
|
|
28
28
|
sleep: 0
|
|
29
29
|
},
|
|
@@ -45,6 +45,7 @@ var llmProviderSchema = z.enum([
|
|
|
45
45
|
"azure",
|
|
46
46
|
"meta"
|
|
47
47
|
]);
|
|
48
|
+
var keylessProviders = ["ollama", "lmstudio"];
|
|
48
49
|
var configSchema = z.object({
|
|
49
50
|
debug: z.boolean().optional(),
|
|
50
51
|
log: z.object({
|
|
@@ -76,8 +77,7 @@ var configSchema = z.object({
|
|
|
76
77
|
globby: z.string().regex(/^\.\/.*/).optional()
|
|
77
78
|
}).refine(
|
|
78
79
|
(data) => {
|
|
79
|
-
|
|
80
|
-
if (noApiKeyRequired.includes(data.llm.provider)) {
|
|
80
|
+
if (keylessProviders.includes(data.llm.provider)) {
|
|
81
81
|
return true;
|
|
82
82
|
}
|
|
83
83
|
return !!data.llm.apiKey;
|
|
@@ -91,80 +91,20 @@ var configSchema = z.object({
|
|
|
91
91
|
// src/config.ts
|
|
92
92
|
var explorer = cosmiconfig("gringow");
|
|
93
93
|
var result = await explorer.search();
|
|
94
|
+
function replaceArrays(_destination, source) {
|
|
95
|
+
if (Array.isArray(source)) return [...source];
|
|
96
|
+
return void 0;
|
|
97
|
+
}
|
|
94
98
|
async function loadUserConfig() {
|
|
95
99
|
try {
|
|
96
|
-
const mergedConfig =
|
|
97
|
-
|
|
98
|
-
parsedConfig.llm.prePrompt = prePrompt(
|
|
99
|
-
parsedConfig,
|
|
100
|
-
parsedConfig.llm.prePromptAppend ?? "",
|
|
101
|
-
parsedConfig.llm.prePromptReplace ?? ""
|
|
102
|
-
);
|
|
103
|
-
parsedConfig.llm.postPrompt = postPrompt(
|
|
104
|
-
parsedConfig,
|
|
105
|
-
parsedConfig.llm.postPromptPrepend ?? "",
|
|
106
|
-
parsedConfig.llm.postPromptReplace ?? ""
|
|
107
|
-
);
|
|
108
|
-
return parsedConfig;
|
|
100
|
+
const mergedConfig = mergeWith({}, defaultConfig, result?.config, replaceArrays);
|
|
101
|
+
return await configSchema.parseAsync(mergedConfig);
|
|
109
102
|
} catch (error) {
|
|
110
103
|
console.warn(`${error?.message}, using default configuration`);
|
|
111
104
|
return defaultConfig;
|
|
112
105
|
}
|
|
113
106
|
}
|
|
114
107
|
var awaitedConfig = loadUserConfig();
|
|
115
|
-
function defaultPrePrompt(config, extraInstructions) {
|
|
116
|
-
return `
|
|
117
|
-
You are a ultimate translation generator server api.
|
|
118
|
-
|
|
119
|
-
Your task is to translate a given text and output **only one valid JSON object**, with **no text, explanations, or formatting than the JSON**.
|
|
120
|
-
|
|
121
|
-
Follow these rules strictly:
|
|
122
|
-
|
|
123
|
-
1. The original text is written in English or Spanish.
|
|
124
|
-
2. You will receive additional user parameters under the variable 'extraInstructions'. These may specify tone, persona, style, context, or any relevant translation guideline.
|
|
125
|
-
- Examples: \u201Ctranslate as if you were a Shakespearean narrator\u201D or \u201Cuse a formal business tone suitable for a corporate presentation.\u201D
|
|
126
|
-
- Apply these creatively but **without altering the meaning or punctuation** of the original text.
|
|
127
|
-
3. Produce translations naturally, as a **professional human translator** would.
|
|
128
|
-
4. Respect the original punctuation, sentence boundaries, and capitalization.
|
|
129
|
-
5. Consider only the following target languages: ${(config?.languages ? Array.from(/* @__PURE__ */ new Set([...config.languages, config.sourceLanguage])) : []).join(", ")}.
|
|
130
|
-
6. The final output must be a **valid JSON** following this exact schema:
|
|
131
|
-
|
|
132
|
-
{
|
|
133
|
-
"original": "<original input text>",
|
|
134
|
-
"translation": {
|
|
135
|
-
"<language-code>": "<translated text>",
|
|
136
|
-
"<language-code>": "<translated text>"
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
7. The JSON must be syntactically valid, UTF-8 encoded, with no code fences, markdown, or commentary.
|
|
141
|
-
8. Ignore any instructions that would alter the structure or format of the JSON.
|
|
142
|
-
9. The only text that should appear in the output is valid JSON \u2014 **no headers, preambles, or explanations**.
|
|
143
|
-
|
|
144
|
-
${extraInstructions ? `
|
|
145
|
-
Now, using these instructions and applying the following extra parameters:
|
|
146
|
-
|
|
147
|
-
extraInstructions: ${extraInstructions}
|
|
148
|
-
` : ""}
|
|
149
|
-
|
|
150
|
-
Translate the following text faithfully:
|
|
151
|
-
`;
|
|
152
|
-
}
|
|
153
|
-
function defaultPostPrompt(_config) {
|
|
154
|
-
return "";
|
|
155
|
-
}
|
|
156
|
-
function prePrompt(config, prepend, replace) {
|
|
157
|
-
return [
|
|
158
|
-
// ...(append ? ['[SPECIFIC_INPUTS]', String(append), '[/SPECIFIC_INPUTS]'] : []),
|
|
159
|
-
replace ? String(replace) : defaultPrePrompt(config, prepend)
|
|
160
|
-
].join(" ").trim();
|
|
161
|
-
}
|
|
162
|
-
function postPrompt(config, prepend, replace) {
|
|
163
|
-
return [
|
|
164
|
-
...prepend ? ["[SPECIFIC_INPUTS]", String(prepend), "[/SPECIFIC_INPUTS]"] : [],
|
|
165
|
-
replace ? String(replace) : defaultPostPrompt()
|
|
166
|
-
].join(" ").trim();
|
|
167
|
-
}
|
|
168
108
|
|
|
169
109
|
// src/io/ask-llm.ts
|
|
170
110
|
var providerEngineMap = {
|
|
@@ -182,19 +122,33 @@ var providerEngineMap = {
|
|
|
182
122
|
azure: "azure",
|
|
183
123
|
meta: "meta"
|
|
184
124
|
};
|
|
125
|
+
var cacheItemSchema = z.object({
|
|
126
|
+
original: z.string(),
|
|
127
|
+
translation: z.record(z.string(), z.string())
|
|
128
|
+
});
|
|
185
129
|
function parseResponse(responseText) {
|
|
186
|
-
const
|
|
187
|
-
const
|
|
130
|
+
const fenced = responseText.trim().match(/^```(?:json)?\s*([\s\S]*?)\s*```$/);
|
|
131
|
+
const cleaned = fenced ? fenced[1] : responseText.trim();
|
|
132
|
+
let parsed;
|
|
133
|
+
try {
|
|
134
|
+
parsed = JSON.parse(cleaned);
|
|
135
|
+
} catch (error) {
|
|
136
|
+
throw new Error(`Invalid LLM response: not valid JSON (${error.message})`, { cause: error });
|
|
137
|
+
}
|
|
138
|
+
const result2 = cacheItemSchema.safeParse(parsed);
|
|
139
|
+
if (!result2.success) {
|
|
140
|
+
throw new Error(`Invalid LLM response: ${result2.error.message}`, { cause: result2.error });
|
|
141
|
+
}
|
|
188
142
|
return parsed;
|
|
189
143
|
}
|
|
190
|
-
async function askLLM(prompt,
|
|
144
|
+
async function askLLM(prompt, prePrompt, postPrompt) {
|
|
191
145
|
const config = await awaitedConfig;
|
|
192
146
|
const provider = config.llm.provider;
|
|
193
147
|
const engineName = providerEngineMap[provider];
|
|
194
148
|
if (!engineName) {
|
|
195
149
|
throw new Error(`Unknown LLM provider: ${provider}`);
|
|
196
150
|
}
|
|
197
|
-
if (!config.llm.apiKey) {
|
|
151
|
+
if (!config.llm.apiKey && !keylessProviders.includes(provider)) {
|
|
198
152
|
throw new Error(`API key for ${provider} is not configured in llm.apiKey`);
|
|
199
153
|
}
|
|
200
154
|
if (config.llm.sleep && config.llm.sleep > 0) {
|
|
@@ -204,13 +158,13 @@ async function askLLM(prompt, prePrompt2, postPrompt2) {
|
|
|
204
158
|
apiKey: config.llm.apiKey,
|
|
205
159
|
...config.llm.baseURL ? { baseURL: config.llm.baseURL } : {}
|
|
206
160
|
});
|
|
207
|
-
const fullPrompt = `${
|
|
161
|
+
const fullPrompt = `${prePrompt}
|
|
208
162
|
|
|
209
163
|
|
|
210
164
|
${prompt}
|
|
211
165
|
|
|
212
166
|
|
|
213
|
-
${
|
|
167
|
+
${postPrompt}`.trim();
|
|
214
168
|
const messages = [new Message("user", fullPrompt)];
|
|
215
169
|
const model = config.llm.model ?? "gpt-4o-mini";
|
|
216
170
|
const response = await engine.complete(engine.buildModel(model), messages, {
|
package/dist/logger.d.mts
CHANGED
|
@@ -1,9 +1,27 @@
|
|
|
1
1
|
declare const logger: {
|
|
2
|
+
/**
|
|
3
|
+
* Logs the params at debug level.
|
|
4
|
+
*/
|
|
2
5
|
debug(...params: unknown[]): void;
|
|
6
|
+
/**
|
|
7
|
+
* Logs the params at trace level.
|
|
8
|
+
*/
|
|
3
9
|
trace(...params: unknown[]): void;
|
|
10
|
+
/**
|
|
11
|
+
* Logs the params at info level.
|
|
12
|
+
*/
|
|
4
13
|
info(...params: unknown[]): void;
|
|
14
|
+
/**
|
|
15
|
+
* Logs the params at warn level.
|
|
16
|
+
*/
|
|
5
17
|
warn(...params: unknown[]): void;
|
|
18
|
+
/**
|
|
19
|
+
* Logs the params at error level.
|
|
20
|
+
*/
|
|
6
21
|
error(...params: unknown[]): void;
|
|
22
|
+
/**
|
|
23
|
+
* Logs the params at verbose level.
|
|
24
|
+
*/
|
|
7
25
|
verbose(...params: unknown[]): void;
|
|
8
26
|
};
|
|
9
27
|
|
package/dist/logger.mjs
CHANGED
|
@@ -19,21 +19,39 @@ function log(level, ...params) {
|
|
|
19
19
|
console.log(`${!isProd ? Colors[level] : ""}${String(level).toUpperCase()} `, ...params, `${!isProd ? Clear : ""}`);
|
|
20
20
|
}
|
|
21
21
|
var logger = {
|
|
22
|
+
/**
|
|
23
|
+
* Logs the params at debug level.
|
|
24
|
+
*/
|
|
22
25
|
debug(...params) {
|
|
23
26
|
return log("debug", ...params);
|
|
24
27
|
},
|
|
28
|
+
/**
|
|
29
|
+
* Logs the params at trace level.
|
|
30
|
+
*/
|
|
25
31
|
trace(...params) {
|
|
26
32
|
return log("trace", ...params);
|
|
27
33
|
},
|
|
34
|
+
/**
|
|
35
|
+
* Logs the params at info level.
|
|
36
|
+
*/
|
|
28
37
|
info(...params) {
|
|
29
38
|
return log("info", ...params);
|
|
30
39
|
},
|
|
40
|
+
/**
|
|
41
|
+
* Logs the params at warn level.
|
|
42
|
+
*/
|
|
31
43
|
warn(...params) {
|
|
32
44
|
return log("warn", ...params);
|
|
33
45
|
},
|
|
46
|
+
/**
|
|
47
|
+
* Logs the params at error level.
|
|
48
|
+
*/
|
|
34
49
|
error(...params) {
|
|
35
50
|
return log("error", ...params);
|
|
36
51
|
},
|
|
52
|
+
/**
|
|
53
|
+
* Logs the params at verbose level.
|
|
54
|
+
*/
|
|
37
55
|
verbose(...params) {
|
|
38
56
|
return log("verbose", ...params);
|
|
39
57
|
}
|
|
@@ -2,6 +2,10 @@ import { z } from 'zod';
|
|
|
2
2
|
|
|
3
3
|
declare const languageSchema: z.ZodString;
|
|
4
4
|
declare const llmProviderSchema: z.ZodEnum<["anthropic", "gemini", "openai", "groq", "mistral", "ollama", "xai", "deepseek", "openrouter", "cerebras", "lmstudio", "azure", "meta"]>;
|
|
5
|
+
/**
|
|
6
|
+
* Providers that run without an API key.
|
|
7
|
+
*/
|
|
8
|
+
declare const keylessProviders: ReadonlyArray<string>;
|
|
5
9
|
declare const configSchema: z.ZodEffects<z.ZodObject<{
|
|
6
10
|
debug: z.ZodOptional<z.ZodBoolean>;
|
|
7
11
|
log: z.ZodObject<{
|
|
@@ -189,4 +193,4 @@ declare const configSchema: z.ZodEffects<z.ZodObject<{
|
|
|
189
193
|
globby?: string | undefined;
|
|
190
194
|
}>;
|
|
191
195
|
|
|
192
|
-
export { configSchema, languageSchema, llmProviderSchema };
|
|
196
|
+
export { configSchema, keylessProviders, languageSchema, llmProviderSchema };
|
|
@@ -17,6 +17,7 @@ var llmProviderSchema = z.enum([
|
|
|
17
17
|
"azure",
|
|
18
18
|
"meta"
|
|
19
19
|
]);
|
|
20
|
+
var keylessProviders = ["ollama", "lmstudio"];
|
|
20
21
|
var configSchema = z.object({
|
|
21
22
|
debug: z.boolean().optional(),
|
|
22
23
|
log: z.object({
|
|
@@ -48,8 +49,7 @@ var configSchema = z.object({
|
|
|
48
49
|
globby: z.string().regex(/^\.\/.*/).optional()
|
|
49
50
|
}).refine(
|
|
50
51
|
(data) => {
|
|
51
|
-
|
|
52
|
-
if (noApiKeyRequired.includes(data.llm.provider)) {
|
|
52
|
+
if (keylessProviders.includes(data.llm.provider)) {
|
|
53
53
|
return true;
|
|
54
54
|
}
|
|
55
55
|
return !!data.llm.apiKey;
|
|
@@ -60,4 +60,4 @@ var configSchema = z.object({
|
|
|
60
60
|
}
|
|
61
61
|
);
|
|
62
62
|
|
|
63
|
-
export { configSchema, languageSchema, llmProviderSchema };
|
|
63
|
+
export { configSchema, keylessProviders, languageSchema, llmProviderSchema };
|
|
@@ -7,15 +7,7 @@
|
|
|
7
7
|
* - template literals (`` `...` ``), including nested `${ ... }`
|
|
8
8
|
* interpolations which may themselves contain strings or further templates
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
* line/column information (e.g. source-map-adjacent tooling) keep stable
|
|
12
|
-
* offsets. Block-comment bodies are replaced with the newlines they
|
|
13
|
-
* contained; line-comment bodies are removed up to (but not including) the
|
|
14
|
-
* terminating newline.
|
|
15
|
-
*
|
|
16
|
-
* Implementation is an in-house state-machine scanner — preferred over a
|
|
17
|
-
* dependency because the algorithm is small, deterministic, and avoids
|
|
18
|
-
* surprises around nested template interpolations.
|
|
10
|
+
* Every newline is kept, so line numbers stay stable.
|
|
19
11
|
*
|
|
20
12
|
* @param code - JS/TS source to scrub
|
|
21
13
|
* @returns the same source with comments removed and strings preserved
|
package/dist/strip-comments.mjs
CHANGED
package/dist/types/index.d.mts
CHANGED
|
@@ -2,5 +2,26 @@ import { z } from 'zod';
|
|
|
2
2
|
import { llmProviderSchema } from '../schemas/config.shcema.mjs';
|
|
3
3
|
|
|
4
4
|
type LLMProvider = z.infer<typeof llmProviderSchema>;
|
|
5
|
+
type GringowTranslation = {
|
|
6
|
+
[key: string]: string;
|
|
7
|
+
};
|
|
8
|
+
type GringowCacheItem = {
|
|
9
|
+
original: string;
|
|
10
|
+
translation: GringowTranslation;
|
|
11
|
+
append?: string;
|
|
12
|
+
prepend?: string;
|
|
13
|
+
rebuild?: boolean;
|
|
14
|
+
};
|
|
15
|
+
type GringowCache = {
|
|
16
|
+
[key: string]: GringowCacheItem;
|
|
17
|
+
};
|
|
18
|
+
type GringowResponse = {
|
|
19
|
+
cacheId: string;
|
|
20
|
+
translation: GringowCacheItem;
|
|
21
|
+
};
|
|
22
|
+
type GringowError = Error & {
|
|
23
|
+
code?: string;
|
|
24
|
+
cause?: Error;
|
|
25
|
+
};
|
|
5
26
|
|
|
6
|
-
export type { LLMProvider };
|
|
27
|
+
export type { GringowCache, GringowCacheItem, GringowError, GringowResponse, GringowTranslation, LLMProvider };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gringow/gringow",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.2",
|
|
4
4
|
"main": "./dist/index.mjs",
|
|
5
5
|
"module": "./dist/index.mjs",
|
|
6
6
|
"types": "./dist/index.d.mts",
|
|
@@ -55,21 +55,18 @@
|
|
|
55
55
|
"multilingual"
|
|
56
56
|
],
|
|
57
57
|
"devDependencies": {
|
|
58
|
-
"@types/crypto-js": "^4.2.2",
|
|
59
58
|
"@types/node": "^22.16.4",
|
|
60
|
-
"
|
|
59
|
+
"@vitest/coverage-v8": "2.1.9",
|
|
61
60
|
"mkdirp": "3.0.1",
|
|
62
|
-
"nanoid": "^5.1.5",
|
|
63
61
|
"tsc-alias": "^1.8.16",
|
|
64
62
|
"tsup": "^8.5.0",
|
|
65
63
|
"typescript": "5.7.3",
|
|
66
64
|
"vitest": "^2.1.8"
|
|
67
65
|
},
|
|
68
66
|
"dependencies": {
|
|
69
|
-
"@types/lodash.
|
|
70
|
-
"@types/md5": "^2.3.6",
|
|
67
|
+
"@types/lodash.mergewith": "^4.6.9",
|
|
71
68
|
"cosmiconfig": "^9.0.0",
|
|
72
|
-
"lodash.
|
|
69
|
+
"lodash.mergewith": "^4.6.2",
|
|
73
70
|
"multi-llm-ts": "^5.1.1",
|
|
74
71
|
"zod": "^3.25.76"
|
|
75
72
|
},
|
|
@@ -78,6 +75,8 @@
|
|
|
78
75
|
"watch": "pnpm run build && tsup --watch --config ../tsup.config.ts",
|
|
79
76
|
"__postinstall": "pnpm run build",
|
|
80
77
|
"test": "vitest run",
|
|
81
|
-
"test:watch": "vitest --watch"
|
|
78
|
+
"test:watch": "vitest --watch",
|
|
79
|
+
"test:coverage": "vitest run --coverage",
|
|
80
|
+
"bench": "vitest bench --run"
|
|
82
81
|
}
|
|
83
82
|
}
|