@gringow/gringow 0.0.1 → 0.0.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/.nvmrc +1 -0
- package/README.md +86 -2
- package/gringow.config.js.example +16 -0
- package/gringow.config.json.example +11 -0
- package/gringow.json +12 -0
- package/package.json +68 -4
- package/src/browser.ts +4 -0
- package/src/config.ts +93 -0
- package/src/data/check-cache.ts +15 -0
- package/src/data/clear-cache.ts +5 -0
- package/src/data/create-cache-dir.ts +7 -0
- package/src/data/create-cache-id.ts +17 -0
- package/src/data/delete-cache-item.ts +20 -0
- package/src/data/get-cache.ts +17 -0
- package/src/data/get-or-create-cache.ts +21 -0
- package/src/data/save-cache.ts +17 -0
- package/src/data/write-cache-to-disk.ts +20 -0
- package/src/default-config.ts +27 -0
- package/src/flat-template-string.test.ts +109 -0
- package/src/flat-template-string.ts +27 -0
- package/src/gringow.ts +49 -0
- package/src/index.ts +37 -0
- package/src/io/anthropic/ask.ts +31 -0
- package/src/io/anthropic/commit-response.ts +11 -0
- package/src/io/anthropic/index.ts +3 -0
- package/src/io/anthropic/parse.ts +11 -0
- package/src/io/ask-llm.ts +44 -0
- package/src/io/gemini/ask.ts +65 -0
- package/src/io/gemini/commit-response.ts +6 -0
- package/src/io/gemini/index.ts +3 -0
- package/src/io/gemini/parse.ts +12 -0
- package/src/io/huggingface/ask.ts +82 -0
- package/src/io/huggingface/commit-response.ts +16 -0
- package/src/io/huggingface/index.ts +16 -0
- package/src/io/huggingface/languagesMap.ts +189 -0
- package/src/io/huggingface/parse.ts +10 -0
- package/src/logger.ts +25 -0
- package/src/schemas/config.shcema.ts +58 -0
- package/src/types/index.ts +22 -0
- package/tsconfig.json +29 -0
- package/tsup.config.ts +21 -0
- package/vitest.config.ts +8 -0
package/src/index.ts
CHANGED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import '@/config'
|
|
2
|
+
|
|
3
|
+
export type GringowTranslation = {
|
|
4
|
+
[key: string]: string
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export type GringowCacheItem = {
|
|
8
|
+
original: string
|
|
9
|
+
translation: GringowTranslation
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type GringowCache = {
|
|
13
|
+
[key: string]: GringowCacheItem
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export type GringowResponse = {
|
|
17
|
+
cacheId: string
|
|
18
|
+
translation: GringowCacheItem
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type GringowError = Error & {
|
|
22
|
+
code?: string
|
|
23
|
+
cause?: Error
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export { awaitedConfig, getConfigSource, isLocalConfigFound } from '@/config'
|
|
27
|
+
export { checkCache } from '@/data/check-cache'
|
|
28
|
+
export { clearCache } from '@/data/clear-cache'
|
|
29
|
+
export { createCacheId } from '@/data/create-cache-id'
|
|
30
|
+
export { deleteCacheItem } from '@/data/delete-cache-item'
|
|
31
|
+
export { getCache } from '@/data/get-cache'
|
|
32
|
+
export { getOrCreateCache } from '@/data/get-or-create-cache'
|
|
33
|
+
export { writeCacheToDisk } from '@/data/write-cache-to-disk'
|
|
34
|
+
export { flatTemplateString } from '@/flat-template-string'
|
|
35
|
+
export { Gringow as default } from '@/gringow'
|
|
36
|
+
|
|
37
|
+
export type { GringowConfig } from '@/default-config'
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import Anthropic from '@anthropic-ai/sdk'
|
|
2
|
+
import { awaitedConfig } from '@/config'
|
|
3
|
+
|
|
4
|
+
export async function askAnthropic(message: string) {
|
|
5
|
+
const config = await awaitedConfig
|
|
6
|
+
if (Number(config.llm.sleep)) {
|
|
7
|
+
await new Promise((resolve) => setTimeout(resolve, config.llm.sleep ?? 1))
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
if (!config.keys.anthropicApiKey) {
|
|
11
|
+
throw new Error('Anthropic API key is not set in the config')
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const anthropic = new Anthropic({
|
|
15
|
+
apiKey: config.keys.anthropicApiKey,
|
|
16
|
+
dangerouslyAllowBrowser: true,
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
const response = await anthropic.messages.create({
|
|
20
|
+
model: config.llm.model as Anthropic.Model,
|
|
21
|
+
max_tokens: 1024,
|
|
22
|
+
messages: [
|
|
23
|
+
{
|
|
24
|
+
role: 'user',
|
|
25
|
+
content: `${config.llm.prePrompt}\n\n\n${message}\n\n\n${config.llm.postPrompt}`,
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
return response as Anthropic.Messages.Message
|
|
31
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Anthropic } from '@anthropic-ai/sdk'
|
|
2
|
+
import type { CommitResponse } from '@/types'
|
|
3
|
+
|
|
4
|
+
export function commitResponseAnthropic(response: Anthropic.Messages.Message) {
|
|
5
|
+
const result = response.content.reduce((acc: string, item: Anthropic.Messages.ContentBlock) => {
|
|
6
|
+
const nextAcc = acc + (item.type === 'text' ? item.text : '')
|
|
7
|
+
return nextAcc
|
|
8
|
+
}, '')
|
|
9
|
+
|
|
10
|
+
return result as CommitResponse
|
|
11
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { GringowCacheItem } from '@/index'
|
|
2
|
+
import type { CommitResponse } from '@/types'
|
|
3
|
+
|
|
4
|
+
export function parseAnthropic(unparsed: CommitResponse): GringowCacheItem {
|
|
5
|
+
if (typeof unparsed !== 'string') {
|
|
6
|
+
throw new Error('CommitResponse should be a string here.')
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const parsed = JSON.parse(unparsed) as GringowCacheItem
|
|
10
|
+
return parsed
|
|
11
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { awaitedConfig } from '@/config'
|
|
2
|
+
import { askAnthropic, commitResponseAnthropic, parseAnthropic } from './anthropic'
|
|
3
|
+
import { askGemini, commitResponseGemini, parseGemini } from './gemini'
|
|
4
|
+
import { askHuggingface, commitResponseHuggingface, parseHuggingface } from './huggingface'
|
|
5
|
+
|
|
6
|
+
import type { GringowCacheItem } from '@/index'
|
|
7
|
+
import type { LLMChoice, LLMChoices, LLMOptions } from '@/types'
|
|
8
|
+
|
|
9
|
+
const llmChoices: LLMChoices = {
|
|
10
|
+
anthropic: {
|
|
11
|
+
ask: askAnthropic,
|
|
12
|
+
commitResponse: commitResponseAnthropic,
|
|
13
|
+
parse: parseAnthropic,
|
|
14
|
+
},
|
|
15
|
+
gemini: {
|
|
16
|
+
ask: askGemini,
|
|
17
|
+
commitResponse: commitResponseGemini,
|
|
18
|
+
parse: parseGemini,
|
|
19
|
+
},
|
|
20
|
+
huggingface: {
|
|
21
|
+
ask: askHuggingface,
|
|
22
|
+
commitResponse: commitResponseHuggingface,
|
|
23
|
+
parse: parseHuggingface,
|
|
24
|
+
},
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async function processChoice<T = { test: number }>(choice: LLMChoice<T>, prompt: string): Promise<GringowCacheItem> {
|
|
28
|
+
const response = await choice.ask(prompt)
|
|
29
|
+
const unparsed = choice.commitResponse(response)
|
|
30
|
+
const parsed = choice.parse(unparsed)
|
|
31
|
+
return parsed
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export async function askLLM(prompt: string): Promise<GringowCacheItem> {
|
|
35
|
+
const config = await awaitedConfig
|
|
36
|
+
const llmChoiceName = config.llm.choice as LLMOptions
|
|
37
|
+
const llmChoice = llmChoices[llmChoiceName]
|
|
38
|
+
|
|
39
|
+
if (!llmChoice) {
|
|
40
|
+
throw new Error('LLMChoice not found')
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return processChoice<Awaited<ReturnType<typeof llmChoice.ask>>>(llmChoice, prompt)
|
|
44
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { type GenerateContentResult, GoogleGenerativeAI } from '@google/generative-ai'
|
|
2
|
+
|
|
3
|
+
import { awaitedConfig } from '@/config'
|
|
4
|
+
|
|
5
|
+
async function generateResponse(message: string, temperature: number = 1.0) {
|
|
6
|
+
const config = await awaitedConfig
|
|
7
|
+
if (!config.keys.geminiApiKey) {
|
|
8
|
+
throw new Error('Gemini API key is not set in the config')
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const generativeAIClient = new GoogleGenerativeAI(config.keys.geminiApiKey)
|
|
12
|
+
const model = generativeAIClient.getGenerativeModel({
|
|
13
|
+
model: config.llm.model as string,
|
|
14
|
+
generationConfig: {
|
|
15
|
+
temperature,
|
|
16
|
+
},
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
const prompt = String(`${config.llm.prePrompt}\n\n\n${message}\n\n\n${config.llm.postPrompt}`).trim()
|
|
20
|
+
if (config.debug) {
|
|
21
|
+
console.log('Gemini model prompt:', JSON.stringify({ prompt }))
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const response = await model.generateContent([prompt])
|
|
25
|
+
|
|
26
|
+
return response
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function askGemini(message: string) {
|
|
30
|
+
const config = await awaitedConfig
|
|
31
|
+
if (Number(config.llm.sleep)) {
|
|
32
|
+
await new Promise((resolve) => setTimeout(resolve, config.llm.sleep ?? 1))
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (!config.keys.geminiApiKey) {
|
|
36
|
+
throw new Error('Gemini API key is not set in the config')
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (config.debug) {
|
|
40
|
+
console.log('\nAsking Gemini model:', JSON.stringify({ model: config.llm.model, message }))
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
let response: GenerateContentResult | undefined
|
|
44
|
+
for (let i = 0; i < 3; i++) {
|
|
45
|
+
const maybeResponse = await generateResponse(message, config.llm.temperature)
|
|
46
|
+
if (!String(maybeResponse.response.candidates?.[0]?.content?.parts?.[0]?.text ?? '').includes('```json')) {
|
|
47
|
+
response = maybeResponse
|
|
48
|
+
break
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (config.debug) {
|
|
52
|
+
console.log('Gemini model response is not valid, contains no JSON:', JSON.stringify({ maybeResponse }))
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (config.debug) {
|
|
57
|
+
console.log('Gemini model response:', JSON.stringify({ response }))
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (!response) {
|
|
61
|
+
throw new Error('Gemini model response is not valid')
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return response
|
|
65
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { GringowCacheItem } from '@/index'
|
|
2
|
+
import type { CommitResponse } from '@/types'
|
|
3
|
+
|
|
4
|
+
export function parseGemini(unparsed: CommitResponse): GringowCacheItem {
|
|
5
|
+
if (typeof unparsed !== 'string') {
|
|
6
|
+
throw new Error('CommitResponse should be a string here.')
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const cleaned = unparsed.replace(/```json/g, '').replace(/```/g, '')
|
|
10
|
+
const parsed = JSON.parse(cleaned) as GringowCacheItem
|
|
11
|
+
return parsed
|
|
12
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import {
|
|
2
|
+
env,
|
|
3
|
+
type ProgressInfo,
|
|
4
|
+
pipeline,
|
|
5
|
+
type TranslationPipeline,
|
|
6
|
+
type TranslationSingle,
|
|
7
|
+
} from '@huggingface/transformers'
|
|
8
|
+
import 'node:fs'
|
|
9
|
+
|
|
10
|
+
import { awaitedConfig } from '@/config'
|
|
11
|
+
import { languagesMap } from './languagesMap'
|
|
12
|
+
|
|
13
|
+
import type { AskHuggingfaceResponse, AskHuggingfaceResponseTranslation } from '@/io/huggingface'
|
|
14
|
+
|
|
15
|
+
function getLanguageCode(language: string) {
|
|
16
|
+
return languagesMap[language as keyof typeof languagesMap]
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function progressCallback(progress: ProgressInfo) {
|
|
20
|
+
process.stdout.clearLine(0)
|
|
21
|
+
process.stdout.cursorTo(0)
|
|
22
|
+
if (progress.status === 'download') {
|
|
23
|
+
process.stdout.write('Downloading...')
|
|
24
|
+
} else if (progress.status === 'initiate') {
|
|
25
|
+
process.stdout.write('Initializing...')
|
|
26
|
+
} else if (progress.status === 'done') {
|
|
27
|
+
process.stdout.write('Done!')
|
|
28
|
+
} else if (progress.status === 'progress' && 'progress' in progress && 'loaded' in progress && 'total' in progress) {
|
|
29
|
+
process.stdout.write(
|
|
30
|
+
`Downloading: ${Number(progress.progress).toFixed(2)}%, loaded: ${progress.loaded}/${progress.total}`
|
|
31
|
+
)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function pipeLanguage(pipe: TranslationPipeline, original: string, srcLanguage: string, targetLanguage: string) {
|
|
36
|
+
const response = await pipe(original, {
|
|
37
|
+
src_lang: srcLanguage,
|
|
38
|
+
tgt_lang: targetLanguage,
|
|
39
|
+
temperature: 1.0,
|
|
40
|
+
} as Parameters<TranslationPipeline['call']>[1])
|
|
41
|
+
|
|
42
|
+
return response
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export async function askHuggingface(original: string) {
|
|
46
|
+
const config = await awaitedConfig
|
|
47
|
+
const cacheDir = `${config.cache.dir}/.cache`
|
|
48
|
+
env.cacheDir = cacheDir
|
|
49
|
+
|
|
50
|
+
const pipe = await pipeline('translation', config.llm.model as string, {
|
|
51
|
+
progress_callback: progressCallback,
|
|
52
|
+
cache_dir: cacheDir,
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
const { languages } = config
|
|
56
|
+
|
|
57
|
+
let responses: AskHuggingfaceResponseTranslation[] = []
|
|
58
|
+
for await (const language of languages) {
|
|
59
|
+
const response = await pipeLanguage(
|
|
60
|
+
pipe,
|
|
61
|
+
original,
|
|
62
|
+
getLanguageCode(config.sourceLanguage),
|
|
63
|
+
getLanguageCode(language)
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
if (Array.isArray(response)) {
|
|
67
|
+
responses = responses.concat(
|
|
68
|
+
response.map((r) => ({
|
|
69
|
+
...r,
|
|
70
|
+
targetLanguage: language,
|
|
71
|
+
})) as AskHuggingfaceResponseTranslation[]
|
|
72
|
+
)
|
|
73
|
+
} else {
|
|
74
|
+
responses.push({
|
|
75
|
+
...(response as TranslationSingle),
|
|
76
|
+
targetLanguage: language,
|
|
77
|
+
} as AskHuggingfaceResponseTranslation)
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return { responses, original } as AskHuggingfaceResponse
|
|
82
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { GringowTranslation } from '@/index'
|
|
2
|
+
import type { AskHuggingfaceResponse } from '@/io/huggingface'
|
|
3
|
+
import type { CommitResponse } from '@/types'
|
|
4
|
+
|
|
5
|
+
export function commitResponseHuggingface(response: AskHuggingfaceResponse) {
|
|
6
|
+
const { responses, original } = response
|
|
7
|
+
const translation = responses.reduce((acc, curr) => {
|
|
8
|
+
acc[curr.targetLanguage] = curr.translation_text
|
|
9
|
+
return acc
|
|
10
|
+
}, {} as GringowTranslation)
|
|
11
|
+
|
|
12
|
+
return {
|
|
13
|
+
translation,
|
|
14
|
+
original,
|
|
15
|
+
} as CommitResponse
|
|
16
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { TranslationSingle } from '@huggingface/transformers'
|
|
2
|
+
|
|
3
|
+
export type AskHuggingfaceResponseTranslation = TranslationSingle & {
|
|
4
|
+
targetLanguage: string
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export type AskHuggingfaceResponse = {
|
|
8
|
+
responses: AskHuggingfaceResponseTranslation[]
|
|
9
|
+
original: string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type AskHuggingfaceResult = string
|
|
13
|
+
|
|
14
|
+
export * from './ask'
|
|
15
|
+
export * from './commit-response'
|
|
16
|
+
export * from './parse'
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
export const languagesMap = {
|
|
2
|
+
'en-US': 'eng_Latn',
|
|
3
|
+
'en-GB': 'eng_Latn',
|
|
4
|
+
'pt-BR': 'por_Latn',
|
|
5
|
+
'pt-PT': 'por_Latn',
|
|
6
|
+
'es-ES': 'spa_Latn',
|
|
7
|
+
'es-MX': 'spa_Latn',
|
|
8
|
+
'fr-FR': 'fra_Latn',
|
|
9
|
+
'fr-CA': 'fra_Latn',
|
|
10
|
+
'de-DE': 'deu_Latn',
|
|
11
|
+
'it-IT': 'ita_Latn',
|
|
12
|
+
'nl-NL': 'nld_Latn',
|
|
13
|
+
'pl-PL': 'pol_Latn',
|
|
14
|
+
'ru-RU': 'rus_Cyrl',
|
|
15
|
+
'uk-UA': 'ukr_Cyrl',
|
|
16
|
+
'bg-BG': 'bul_Cyrl',
|
|
17
|
+
'hr-HR': 'hrv_Latn',
|
|
18
|
+
'cs-CZ': 'ces_Latn',
|
|
19
|
+
'sk-SK': 'slk_Latn',
|
|
20
|
+
'hu-HU': 'hun_Latn',
|
|
21
|
+
'ro-RO': 'ron_Latn',
|
|
22
|
+
'fi-FI': 'fin_Latn',
|
|
23
|
+
'sv-SE': 'swe_Latn',
|
|
24
|
+
'da-DK': 'dan_Latn',
|
|
25
|
+
'no-NO': 'nob_Latn',
|
|
26
|
+
'is-IS': 'isl_Latn',
|
|
27
|
+
'et-EE': 'est_Latn',
|
|
28
|
+
'lv-LV': 'lav_Latn',
|
|
29
|
+
'lt-LT': 'lit_Latn',
|
|
30
|
+
'mt-MT': 'mlt_Latn',
|
|
31
|
+
'ga-IE': 'gle_Latn',
|
|
32
|
+
'cy-GB': 'cym_Latn',
|
|
33
|
+
'eu-ES': 'eus_Latn',
|
|
34
|
+
'ca-ES': 'cat_Latn',
|
|
35
|
+
'gl-ES': 'glg_Latn',
|
|
36
|
+
'oc-FR': 'oci_Latn',
|
|
37
|
+
'br-FR': 'bre_Latn',
|
|
38
|
+
'gd-GB': 'gla_Latn',
|
|
39
|
+
'kw-GB': 'cor_Latn',
|
|
40
|
+
'fur-IT': 'fur_Latn',
|
|
41
|
+
'rm-CH': 'roh_Latn',
|
|
42
|
+
'lb-LU': 'ltz_Latn',
|
|
43
|
+
'fy-NL': 'fry_Latn',
|
|
44
|
+
'af-ZA': 'afr_Latn',
|
|
45
|
+
|
|
46
|
+
'zh-CN': 'zho_Hans',
|
|
47
|
+
'zh-TW': 'zho_Hant',
|
|
48
|
+
'zh-HK': 'zho_Hant',
|
|
49
|
+
'ja-JP': 'jpn_Jpan',
|
|
50
|
+
'ko-KR': 'kor_Hang',
|
|
51
|
+
'th-TH': 'tha_Thai',
|
|
52
|
+
'vi-VN': 'vie_Latn',
|
|
53
|
+
'id-ID': 'ind_Latn',
|
|
54
|
+
'ms-MY': 'zsm_Latn',
|
|
55
|
+
'tl-PH': 'tgl_Latn',
|
|
56
|
+
'my-MM': 'mya_Mymr',
|
|
57
|
+
'km-KH': 'khm_Khmr',
|
|
58
|
+
'lo-LA': 'lao_Laoo',
|
|
59
|
+
'bn-BD': 'ben_Beng',
|
|
60
|
+
'bn-IN': 'ben_Beng',
|
|
61
|
+
'hi-IN': 'hin_Deva',
|
|
62
|
+
'ur-PK': 'urd_Arab',
|
|
63
|
+
'ur-IN': 'urd_Arab',
|
|
64
|
+
'pa-IN': 'pan_Guru',
|
|
65
|
+
'gu-IN': 'guj_Gujr',
|
|
66
|
+
'or-IN': 'ory_Orya',
|
|
67
|
+
'as-IN': 'asm_Beng',
|
|
68
|
+
'ml-IN': 'mal_Mlym',
|
|
69
|
+
'ta-IN': 'tam_Tamil',
|
|
70
|
+
'te-IN': 'tel_Telu',
|
|
71
|
+
'kn-IN': 'kan_Knda',
|
|
72
|
+
'si-LK': 'sin_Sinh',
|
|
73
|
+
'ne-NP': 'nep_Deva',
|
|
74
|
+
'dz-BT': 'dzo_Tibt',
|
|
75
|
+
'bo-CN': 'bod_Tibt',
|
|
76
|
+
'mn-MN': 'khk_Cyrl',
|
|
77
|
+
'ka-GE': 'kat_Geor',
|
|
78
|
+
'hy-AM': 'hye_Armn',
|
|
79
|
+
'az-AZ': 'azj_Latn',
|
|
80
|
+
'tr-TR': 'tur_Latn',
|
|
81
|
+
'fa-IR': 'pes_Arab',
|
|
82
|
+
'fa-AF': 'pes_Arab',
|
|
83
|
+
'ps-AF': 'pbt_Arab',
|
|
84
|
+
'ku-TR': 'kmr_Latn',
|
|
85
|
+
'he-IL': 'heb_Hebr',
|
|
86
|
+
'ar-SA': 'arb_Arab',
|
|
87
|
+
'ar-EG': 'arb_Arab',
|
|
88
|
+
'ar-MA': 'arb_Arab',
|
|
89
|
+
'ar-DZ': 'arb_Arab',
|
|
90
|
+
'ar-TN': 'arb_Arab',
|
|
91
|
+
'ar-LY': 'arb_Arab',
|
|
92
|
+
'ar-SD': 'arb_Arab',
|
|
93
|
+
'ar-IQ': 'arb_Arab',
|
|
94
|
+
'ar-SY': 'arb_Arab',
|
|
95
|
+
'ar-JO': 'arb_Arab',
|
|
96
|
+
'ar-LB': 'arb_Arab',
|
|
97
|
+
'ar-KW': 'arb_Arab',
|
|
98
|
+
'ar-AE': 'arb_Arab',
|
|
99
|
+
'ar-QA': 'arb_Arab',
|
|
100
|
+
'ar-BH': 'arb_Arab',
|
|
101
|
+
'ar-OM': 'arb_Arab',
|
|
102
|
+
'ar-YE': 'arb_Arab',
|
|
103
|
+
'ar-SO': 'arb_Arab',
|
|
104
|
+
'ar-DJ': 'arb_Arab',
|
|
105
|
+
'ar-KM': 'arb_Arab',
|
|
106
|
+
'ar-TD': 'arb_Arab',
|
|
107
|
+
'ar-ER': 'arb_Arab',
|
|
108
|
+
'ar-IL': 'arb_Arab',
|
|
109
|
+
'ar-PS': 'arb_Arab',
|
|
110
|
+
'ar-001': 'arb_Arab',
|
|
111
|
+
|
|
112
|
+
'sw-KE': 'swh_Latn',
|
|
113
|
+
'sw-TZ': 'swh_Latn',
|
|
114
|
+
'am-ET': 'amh_Ethi',
|
|
115
|
+
'om-ET': 'gaz_Latn',
|
|
116
|
+
'so-SO': 'som_Latn',
|
|
117
|
+
'ha-NG': 'hau_Latn',
|
|
118
|
+
'yo-NG': 'yor_Latn',
|
|
119
|
+
'ig-NG': 'ibo_Latn',
|
|
120
|
+
'zu-ZA': 'zul_Latn',
|
|
121
|
+
'xh-ZA': 'xho_Latn',
|
|
122
|
+
'rw-RW': 'kin_Latn',
|
|
123
|
+
'lg-UG': 'lug_Latn',
|
|
124
|
+
'ak-GH': 'aka_Latn',
|
|
125
|
+
'tw-GH': 'twi_Latn',
|
|
126
|
+
'ee-GH': 'ewe_Latn',
|
|
127
|
+
'ff-SN': 'fuv_Latn',
|
|
128
|
+
'wo-SN': 'wol_Latn',
|
|
129
|
+
'sn-ZW': 'sna_Latn',
|
|
130
|
+
'nd-ZW': 'nde_Latn',
|
|
131
|
+
'ny-MW': 'nya_Latn',
|
|
132
|
+
'st-ZA': 'sot_Latn',
|
|
133
|
+
'tn-BW': 'tsn_Latn',
|
|
134
|
+
'ts-ZA': 'tso_Latn',
|
|
135
|
+
've-ZA': 'ven_Latn',
|
|
136
|
+
'ss-ZA': 'ssw_Latn',
|
|
137
|
+
'nr-ZA': 'nbl_Latn',
|
|
138
|
+
|
|
139
|
+
'qu-PE': 'quy_Latn',
|
|
140
|
+
'qu-BO': 'quy_Latn',
|
|
141
|
+
'qu-EC': 'quy_Latn',
|
|
142
|
+
'ay-BO': 'aym_Latn',
|
|
143
|
+
'gn-PY': 'grn_Latn',
|
|
144
|
+
'ht-HT': 'hat_Latn',
|
|
145
|
+
'jv-ID': 'jav_Latn',
|
|
146
|
+
'su-ID': 'sun_Latn',
|
|
147
|
+
'ceb-PH': 'ceb_Latn',
|
|
148
|
+
'ilo-PH': 'ilo_Latn',
|
|
149
|
+
'war-PH': 'war_Latn',
|
|
150
|
+
'bjn-ID': 'bjn_Latn',
|
|
151
|
+
'ban-ID': 'ban_Latn',
|
|
152
|
+
'mad-ID': 'mad_Latn',
|
|
153
|
+
'min-ID': 'min_Latn',
|
|
154
|
+
'ace-ID': 'ace_Latn',
|
|
155
|
+
'bug-ID': 'bug_Latn',
|
|
156
|
+
'gor-ID': 'gor_Latn',
|
|
157
|
+
'mak-ID': 'mak_Latn',
|
|
158
|
+
'mdr-ID': 'mdr_Latn',
|
|
159
|
+
'sas-ID': 'sas_Latn',
|
|
160
|
+
'shn-MM': 'shn_Mymr',
|
|
161
|
+
'kac-MM': 'kac_Latn',
|
|
162
|
+
'lzh-CN': 'lzh_Hant',
|
|
163
|
+
'wuu-CN': 'wuu_Hans',
|
|
164
|
+
'yue-CN': 'yue_Hant',
|
|
165
|
+
'nan-TW': 'nan_Hant',
|
|
166
|
+
'hak-TW': 'hak_Hant',
|
|
167
|
+
'cjy-CN': 'cjy_Hans',
|
|
168
|
+
'cmn-CN': 'cmn_Hans',
|
|
169
|
+
'cmn-TW': 'cmn_Hant',
|
|
170
|
+
'cmn-SG': 'cmn_Hans',
|
|
171
|
+
'cmn-HK': 'cmn_Hant',
|
|
172
|
+
'cmn-MO': 'cmn_Hant',
|
|
173
|
+
'cmn-001': 'cmn_Hans',
|
|
174
|
+
|
|
175
|
+
'haw-US': 'haw_Latn',
|
|
176
|
+
'mi-NZ': 'mri_Latn',
|
|
177
|
+
'sm-WS': 'smo_Latn',
|
|
178
|
+
'to-TO': 'ton_Latn',
|
|
179
|
+
'fj-FJ': 'fij_Latn',
|
|
180
|
+
'ty-PF': 'tah_Latn',
|
|
181
|
+
'co-FR': 'cos_Latn',
|
|
182
|
+
'eu-FR': 'eus_Latn',
|
|
183
|
+
|
|
184
|
+
'kk-KZ': 'kaz_Cyrl',
|
|
185
|
+
'ky-KG': 'kir_Cyrl',
|
|
186
|
+
'uz-UZ': 'uzn_Latn',
|
|
187
|
+
'tg-TJ': 'tgk_Cyrl',
|
|
188
|
+
'tk-TM': 'tuk_Latn',
|
|
189
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { GringowCacheItem } from '@/index'
|
|
2
|
+
import type { CommitResponse } from '@/types'
|
|
3
|
+
|
|
4
|
+
export function parseHuggingface(unparsed: CommitResponse): GringowCacheItem {
|
|
5
|
+
if (typeof unparsed === 'string') {
|
|
6
|
+
throw new Error('CommitResponse should not be a string here.')
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
return unparsed
|
|
10
|
+
}
|
package/src/logger.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// "error", "warn", "info", "debug", "trace"
|
|
2
|
+
const levels = {
|
|
3
|
+
error: 0,
|
|
4
|
+
warn: 1,
|
|
5
|
+
info: 2,
|
|
6
|
+
debug: 3,
|
|
7
|
+
trace: 4,
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
type Level = keyof typeof levels
|
|
11
|
+
|
|
12
|
+
const currentLevel: Level = 'info'
|
|
13
|
+
const maxLevel = levels[currentLevel]
|
|
14
|
+
|
|
15
|
+
const noop = () => void 0
|
|
16
|
+
|
|
17
|
+
const logger = {
|
|
18
|
+
error: maxLevel >= levels.error ? console.error : noop,
|
|
19
|
+
warn: maxLevel >= levels.warn ? console.warn : noop,
|
|
20
|
+
info: maxLevel >= levels.info ? console.info : noop,
|
|
21
|
+
debug: maxLevel >= levels.debug ? console.debug : noop,
|
|
22
|
+
trace: maxLevel >= levels.trace ? console.trace : noop,
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export default logger
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
|
|
3
|
+
export const languageSchema = z.string().regex(/^[a-z]{2,3}(-[A-Z]{2})?$/)
|
|
4
|
+
|
|
5
|
+
export const llmOptionsSchema = z.enum(['gemini', 'anthropic', 'huggingface'])
|
|
6
|
+
|
|
7
|
+
export const configSchema = z
|
|
8
|
+
.object({
|
|
9
|
+
debug: z.boolean().optional(),
|
|
10
|
+
log: z.object({
|
|
11
|
+
level: z.enum(['debug', 'info', 'warn', 'error', 'trace']),
|
|
12
|
+
}),
|
|
13
|
+
cache: z.object({
|
|
14
|
+
dir: z.string(),
|
|
15
|
+
file: z.string(),
|
|
16
|
+
prefix: z.string(),
|
|
17
|
+
write: z.boolean().optional(),
|
|
18
|
+
}),
|
|
19
|
+
keys: z.object({
|
|
20
|
+
anthropicApiKey: z.string().optional(),
|
|
21
|
+
geminiApiKey: z.string().optional(),
|
|
22
|
+
}),
|
|
23
|
+
sourceLanguage: languageSchema,
|
|
24
|
+
languages: z.array(languageSchema),
|
|
25
|
+
llm: z.object({
|
|
26
|
+
choice: llmOptionsSchema,
|
|
27
|
+
model: z.string().nullable(),
|
|
28
|
+
temperature: z.number().optional(),
|
|
29
|
+
sleep: z.number().optional(),
|
|
30
|
+
prePrompt: z.string().optional(),
|
|
31
|
+
postPrompt: z.string().optional(),
|
|
32
|
+
prePromptReplace: z.string().optional(),
|
|
33
|
+
postPromptReplace: z.string().optional(),
|
|
34
|
+
prePromptAppend: z.string().optional(),
|
|
35
|
+
postPromptAppend: z.string().optional(),
|
|
36
|
+
}),
|
|
37
|
+
globby: z
|
|
38
|
+
.string()
|
|
39
|
+
.regex(/^\.\/.*/)
|
|
40
|
+
.optional(),
|
|
41
|
+
})
|
|
42
|
+
.refine(
|
|
43
|
+
(data) => {
|
|
44
|
+
if (data.llm.choice === 'gemini' && !data.keys.geminiApiKey) {
|
|
45
|
+
return false
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (data.llm.choice === 'anthropic' && !data.keys.anthropicApiKey) {
|
|
49
|
+
return false
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return true
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
message: 'The API key corresponding to the chosen LLM must be present.',
|
|
56
|
+
path: ['keys'],
|
|
57
|
+
}
|
|
58
|
+
)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { z } from 'zod'
|
|
2
|
+
import type { GringowCacheItem, GringowTranslation } from '@/index'
|
|
3
|
+
import type { llmOptionsSchema } from '@/schemas/config.shcema'
|
|
4
|
+
|
|
5
|
+
export type CommitResponse = string | { translation: GringowTranslation; original: string }
|
|
6
|
+
|
|
7
|
+
export type Asker<T> = (message: string) => Promise<T>
|
|
8
|
+
export type Commiter<T> = (response: T) => CommitResponse
|
|
9
|
+
export type Parser = (unparsed: CommitResponse) => GringowCacheItem
|
|
10
|
+
|
|
11
|
+
export type LLMOptions = z.infer<typeof llmOptionsSchema>
|
|
12
|
+
|
|
13
|
+
export type LLMChoice<T> = {
|
|
14
|
+
ask: Asker<T>
|
|
15
|
+
commitResponse: Commiter<T>
|
|
16
|
+
parse: Parser
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export type LLMChoices = {
|
|
20
|
+
// biome-ignore lint/suspicious/noExplicitAny: LLMChoice can receive any type
|
|
21
|
+
[K in LLMOptions]: LLMChoice<any>
|
|
22
|
+
}
|