@gringow/gringow 0.1.3 → 0.2.0

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.
Files changed (49) hide show
  1. package/README.md +279 -43
  2. package/dist/config.d.mts +7 -8
  3. package/dist/config.mjs +32 -20
  4. package/dist/config.test.mjs +39 -25
  5. package/dist/constants/default-config.mjs +4 -3
  6. package/dist/data/check-cache.mjs +33 -63
  7. package/dist/data/clear-cache.mjs +32 -20
  8. package/dist/data/create-cache-dir.mjs +32 -20
  9. package/dist/data/delete-cache-item.mjs +32 -20
  10. package/dist/data/get-cache.mjs +32 -20
  11. package/dist/data/get-or-create-cache.mjs +32 -20
  12. package/dist/data/save-cache.mjs +32 -20
  13. package/dist/data/write-cache-to-disk.mjs +32 -20
  14. package/dist/gringow.mjs +84 -491
  15. package/dist/index.mjs +84 -491
  16. package/dist/io/ask-llm.d.mts +3 -1
  17. package/dist/io/ask-llm.mjs +77 -449
  18. package/dist/schemas/config.shcema.d.mts +40 -47
  19. package/dist/schemas/config.shcema.mjs +26 -15
  20. package/dist/types/index.d.mts +3 -25
  21. package/gringow.config.js.example +2 -4
  22. package/gringow.config.json.example +4 -2
  23. package/package.json +2 -5
  24. package/dist/io/anthropic/ask.d.mts +0 -11
  25. package/dist/io/anthropic/ask.mjs +0 -190
  26. package/dist/io/anthropic/commit-response.d.mts +0 -21
  27. package/dist/io/anthropic/commit-response.mjs +0 -10
  28. package/dist/io/anthropic/index.d.mts +0 -14
  29. package/dist/io/anthropic/index.mjs +0 -208
  30. package/dist/io/anthropic/parse.d.mts +0 -20
  31. package/dist/io/anthropic/parse.mjs +0 -10
  32. package/dist/io/gemini/ask.d.mts +0 -11
  33. package/dist/io/gemini/ask.mjs +0 -232
  34. package/dist/io/gemini/commit-response.d.mts +0 -11
  35. package/dist/io/gemini/commit-response.mjs +0 -7
  36. package/dist/io/gemini/index.d.mts +0 -14
  37. package/dist/io/gemini/index.mjs +0 -248
  38. package/dist/io/gemini/parse.d.mts +0 -20
  39. package/dist/io/gemini/parse.mjs +0 -11
  40. package/dist/io/huggingface/ask.d.mts +0 -13
  41. package/dist/io/huggingface/ask.mjs +0 -405
  42. package/dist/io/huggingface/commit-response.d.mts +0 -39
  43. package/dist/io/huggingface/commit-response.mjs +0 -14
  44. package/dist/io/huggingface/index.d.mts +0 -13
  45. package/dist/io/huggingface/index.mjs +0 -426
  46. package/dist/io/huggingface/languages-map.d.mts +0 -191
  47. package/dist/io/huggingface/languages-map.mjs +0 -187
  48. package/dist/io/huggingface/parse.d.mts +0 -20
  49. package/dist/io/huggingface/parse.mjs +0 -9
package/dist/gringow.mjs CHANGED
@@ -4,9 +4,7 @@ import { z } from 'zod';
4
4
  import fs from 'fs/promises';
5
5
  import { dirname, resolve, parse } from 'path';
6
6
  import { mkdir, stat, statSync, mkdirSync } from 'fs';
7
- import Anthropic from '@anthropic-ai/sdk';
8
- import { GoogleGenerativeAI } from '@google/generative-ai';
9
- import { env, pipeline } from '@huggingface/transformers';
7
+ import { igniteEngine, Message } from 'multi-llm-ts';
10
8
 
11
9
  // src/config.ts
12
10
 
@@ -22,19 +20,34 @@ var defaultConfig = {
22
20
  prefix: "grw",
23
21
  write: true
24
22
  },
25
- keys: {},
26
23
  sourceLanguage: "en-US",
24
+ defaultLanguage: "pt-BR",
27
25
  languages: ["pt-BR", "fr-CA"],
28
26
  llm: {
29
- choice: "huggingface",
30
- model: "Xenova/nllb-200-distilled-600M",
27
+ provider: "openai",
28
+ apiKey: void 0,
29
+ model: "gpt-4o-mini",
31
30
  temperature: 1,
32
31
  sleep: 0
33
32
  },
34
33
  globby: "./src/**/*.{js,jsx,ts,tsx}"
35
34
  };
36
35
  var languageSchema = z.string().regex(/^[a-z]{2,3}(-[A-Z]{2})?$/);
37
- var llmOptionsSchema = z.enum(["gemini", "anthropic", "huggingface"]);
36
+ var llmProviderSchema = z.enum([
37
+ "anthropic",
38
+ "gemini",
39
+ "openai",
40
+ "groq",
41
+ "mistral",
42
+ "ollama",
43
+ "xai",
44
+ "deepseek",
45
+ "openrouter",
46
+ "cerebras",
47
+ "lmstudio",
48
+ "azure",
49
+ "meta"
50
+ ]);
38
51
  var configSchema = z.object({
39
52
  debug: z.boolean().optional(),
40
53
  log: z.object({
@@ -46,14 +59,13 @@ var configSchema = z.object({
46
59
  prefix: z.string(),
47
60
  write: z.boolean().optional()
48
61
  }),
49
- keys: z.object({
50
- anthropicApiKey: z.string().optional(),
51
- geminiApiKey: z.string().optional()
52
- }),
53
62
  sourceLanguage: languageSchema,
63
+ defaultLanguage: languageSchema,
54
64
  languages: z.array(languageSchema),
55
65
  llm: z.object({
56
- choice: llmOptionsSchema,
66
+ provider: llmProviderSchema,
67
+ apiKey: z.string().optional(),
68
+ baseURL: z.string().optional(),
57
69
  model: z.string().nullable(),
58
70
  temperature: z.number().optional(),
59
71
  sleep: z.number().optional(),
@@ -67,17 +79,15 @@ var configSchema = z.object({
67
79
  globby: z.string().regex(/^\.\/.*/).optional()
68
80
  }).refine(
69
81
  (data) => {
70
- if (data.llm.choice === "gemini" && !data.keys.geminiApiKey) {
71
- return false;
72
- }
73
- if (data.llm.choice === "anthropic" && !data.keys.anthropicApiKey) {
74
- return false;
82
+ const noApiKeyRequired = ["ollama", "lmstudio"];
83
+ if (noApiKeyRequired.includes(data.llm.provider)) {
84
+ return true;
75
85
  }
76
- return true;
86
+ return !!data.llm.apiKey;
77
87
  },
78
88
  {
79
- message: "The API key corresponding to the chosen LLM must be present.",
80
- path: ["keys"]
89
+ message: "The API key must be present in llm.apiKey for the chosen provider.",
90
+ path: ["llm", "apiKey"]
81
91
  }
82
92
  );
83
93
 
@@ -113,7 +123,7 @@ Your task is to translate a given text and output **only one valid JSON object**
113
123
 
114
124
  Follow these rules strictly:
115
125
 
116
- 1. The original text is written in English.
126
+ 1. The original text is written in English or Spanish.
117
127
  2. You will receive additional user parameters under the variable 'extraInstructions'. These may specify tone, persona, style, context, or any relevant translation guideline.
118
128
  - Examples: \u201Ctranslate as if you were a Shakespearean narrator\u201D or \u201Cuse a formal business tone suitable for a corporate presentation.\u201D
119
129
  - Apply these creatively but **without altering the meaning or punctuation** of the original text.
@@ -146,10 +156,10 @@ Translate the following text faithfully:
146
156
  function defaultPostPrompt(_config) {
147
157
  return "";
148
158
  }
149
- function prePrompt(config, append, replace) {
159
+ function prePrompt(config, prepend, replace) {
150
160
  return [
151
161
  // ...(append ? ['[SPECIFIC_INPUTS]', String(append), '[/SPECIFIC_INPUTS]'] : []),
152
- replace ? String(replace) : defaultPrePrompt(config, append)
162
+ replace ? String(replace) : defaultPrePrompt(config, prepend)
153
163
  ].join(" ").trim();
154
164
  }
155
165
  function postPrompt(config, prepend, replace) {
@@ -466,53 +476,11 @@ async function getOrCreateCache() {
466
476
  return rawCache ? JSON.parse(rawCache?.toString()) : {};
467
477
  }
468
478
 
469
- // src/logger.ts
470
- var Dim = "\x1B[2m";
471
- var FgGreen = "\x1B[32m";
472
- var FgYellow = "\x1B[33m";
473
- var FgCyan = "\x1B[36m";
474
- var FgWhite = "\x1B[37m";
475
- var BgRed = "\x1B[41m";
476
- var Clear = "\x1B[0m";
477
- var Colors = {
478
- debug: `${Dim}${FgGreen}`,
479
- trace: `${Dim}${FgCyan}`,
480
- info: `${FgCyan}`,
481
- error: `${BgRed}${FgWhite}`,
482
- warn: `${FgYellow}`,
483
- verbose: `${FgWhite}`
484
- };
485
- var isProd = process.env.NODE_ENV === "production";
486
- function log(level, ...params) {
487
- console.log(`${!isProd ? Colors[level] : ""}${String(level).toUpperCase()} `, ...params, `${!isProd ? Clear : ""}`);
488
- }
489
- var logger = {
490
- debug(...params) {
491
- return log("debug", ...params);
492
- },
493
- trace(...params) {
494
- return log("trace", ...params);
495
- },
496
- info(...params) {
497
- return log("info", ...params);
498
- },
499
- warn(...params) {
500
- return log("warn", ...params);
501
- },
502
- error(...params) {
503
- return log("error", ...params);
504
- },
505
- verbose(...params) {
506
- return log("verbose", ...params);
507
- }
508
- };
509
- var logger_default = logger;
510
-
511
479
  // src/data/check-cache.ts
512
480
  async function checkCache(cacheId) {
513
481
  const cache = await getOrCreateCache();
514
482
  if (cache?.[cacheId]) {
515
- logger_default.debug(`Cache hit, id:${cacheId}`);
483
+ console.log(`Cache hit, id:${cacheId}`);
516
484
  return cache[cacheId];
517
485
  }
518
486
  return void 0;
@@ -540,445 +508,62 @@ function flatTemplateString(givenStrings, givenValues) {
540
508
  }, "");
541
509
  return flatted;
542
510
  }
543
- async function askAnthropic(prompt, prePrompt2, postPrompt2) {
544
- const config = await awaitedConfig;
545
- if (Number(config.llm.sleep)) {
546
- await new Promise((resolve2) => setTimeout(resolve2, config.llm.sleep ?? 1));
547
- }
548
- if (!config.keys.anthropicApiKey) {
549
- throw new Error("Anthropic API key is not set in the config");
550
- }
551
- const anthropic = new Anthropic({
552
- apiKey: config.keys.anthropicApiKey,
553
- dangerouslyAllowBrowser: true
554
- });
555
- const fullPrompt = String(`${prePrompt2}
556
-
557
-
558
- ${prompt}
559
-
560
-
561
- ${postPrompt2}`).trim();
562
- const response = await anthropic.messages.create({
563
- model: config.llm.model,
564
- max_tokens: 1024,
565
- messages: [
566
- {
567
- role: "user",
568
- content: fullPrompt
569
- }
570
- ]
571
- });
572
- return response;
573
- }
574
-
575
- // src/io/anthropic/commit-response.ts
576
- function commitResponseAnthropic(response) {
577
- const result2 = response.content.reduce((acc, item) => {
578
- const nextAcc = acc + (item.type === "text" ? item.text : "");
579
- return nextAcc;
580
- }, "");
581
- return result2;
582
- }
583
-
584
- // src/io/anthropic/parse.ts
585
- function parseAnthropic(unparsed) {
586
- if (typeof unparsed !== "string") {
587
- throw new Error("CommitResponse should be a string here.");
588
- }
589
- const parsed = JSON.parse(unparsed);
511
+ var providerEngineMap = {
512
+ anthropic: "anthropic",
513
+ gemini: "google",
514
+ openai: "openai",
515
+ groq: "groq",
516
+ mistral: "mistralai",
517
+ ollama: "ollama",
518
+ xai: "xai",
519
+ deepseek: "deepseek",
520
+ openrouter: "openrouter",
521
+ cerebras: "cerebras",
522
+ lmstudio: "lmstudio",
523
+ azure: "azure",
524
+ meta: "meta"
525
+ };
526
+ function parseResponse(responseText) {
527
+ const cleaned = responseText.replace(/```json/g, "").replace(/```/g, "").trim();
528
+ const parsed = JSON.parse(cleaned);
590
529
  return parsed;
591
530
  }
592
- async function generateResponse(prompt, config) {
593
- try {
594
- if (!config.keys.geminiApiKey) {
595
- throw new Error("Gemini API key is not set in the config");
596
- }
597
- const generativeAIClient = new GoogleGenerativeAI(config.keys.geminiApiKey);
598
- const model = generativeAIClient.getGenerativeModel({
599
- model: config.llm.model,
600
- generationConfig: {
601
- temperature: config.llm.temperature ?? 0.8
602
- }
603
- });
604
- if (config.debug) {
605
- console.log("Gemini model prompt:", JSON.stringify({ prompt }));
606
- }
607
- const response = await model.generateContent([prompt]);
608
- return response;
609
- } catch (err) {
610
- const error = err;
611
- console.log("Error details from Gemini model", JSON.stringify({ error }, null, 2));
612
- const retryDelay = error?.errorDetails?.find(
613
- (detail) => detail?.["@type"] === "type.googleapis.com/google.rpc.RetryInfo"
614
- )?.retryDelay ?? void 0;
615
- if (error.status === 429 && retryDelay !== void 0) {
616
- const sleepTime = config.llm.sleep ?? 3;
617
- console.warn(
618
- `Rate limit exceeded when generating response from Gemini model, retrying in... ${retryDelay} + ${sleepTime / 1e3}s`
619
- );
620
- await new Promise((resolve2) => setTimeout(resolve2, (parseInt(retryDelay, 10) + sleepTime / 1e3) * 1e3));
621
- return generateResponse(prompt, config);
622
- }
623
- console.error("Error generating response from Gemini model", { error });
624
- throw error;
625
- }
626
- }
627
- async function askGemini(prompt, prePrompt2, postPrompt2) {
531
+ async function askLLM(prompt, prePrompt2, postPrompt2) {
628
532
  const config = await awaitedConfig;
629
- if (Number(config.llm.sleep)) {
630
- await new Promise((resolve2) => setTimeout(resolve2, config.llm.sleep ?? 1));
533
+ const provider = config.llm.provider;
534
+ const engineName = providerEngineMap[provider];
535
+ if (!engineName) {
536
+ throw new Error(`Unknown LLM provider: ${provider}`);
631
537
  }
632
- if (!config.keys.geminiApiKey) {
633
- throw new Error("Gemini API key is not set in the config");
538
+ if (!config.llm.apiKey) {
539
+ throw new Error(`API key for ${provider} is not configured in llm.apiKey`);
634
540
  }
635
- if (config.debug) {
636
- console.log("\nAsking Gemini model:", JSON.stringify({ model: config.llm.model, message: prompt }));
541
+ if (config.llm.sleep && config.llm.sleep > 0) {
542
+ await new Promise((resolve2) => setTimeout(resolve2, config.llm.sleep));
637
543
  }
638
- const fullPrompt = String(`${prePrompt2}
544
+ const engine = igniteEngine(engineName, {
545
+ apiKey: config.llm.apiKey,
546
+ ...config.llm.baseURL ? { baseURL: config.llm.baseURL } : {}
547
+ });
548
+ const fullPrompt = `${prePrompt2}
639
549
 
640
550
 
641
551
  ${prompt}
642
552
 
643
553
 
644
- ${postPrompt2}`).trim();
645
- let response;
646
- for (let i = 0; i < 3; i++) {
647
- const maybeResponse = await generateResponse(fullPrompt, config);
648
- const responseString = String(maybeResponse.response.candidates?.[0]?.content?.parts?.[0]?.text ?? "").replace(/```json/g, "").replace(/```/g, "").trim();
649
- if (responseString.startsWith("{") && responseString.endsWith("}")) {
650
- response = maybeResponse;
651
- break;
652
- }
653
- if (config.debug) {
654
- console.log("Gemini model response is not valid, contains no JSON:", JSON.stringify({ maybeResponse }));
655
- }
656
- }
657
- if (config.debug) {
658
- console.log("Gemini model response:", JSON.stringify({ response }));
659
- }
660
- if (!response) {
661
- throw new Error("Gemini model response is not valid");
662
- }
663
- return response;
664
- }
665
-
666
- // src/io/gemini/commit-response.ts
667
- function commitResponseGemini(response) {
668
- const result2 = response.response.text();
669
- return result2;
670
- }
671
-
672
- // src/io/gemini/parse.ts
673
- function parseGemini(unparsed) {
674
- if (typeof unparsed !== "string") {
675
- throw new Error("CommitResponse should be a string here.");
676
- }
677
- const cleaned = unparsed.replace(/```json/g, "").replace(/```/g, "");
678
- const parsed = JSON.parse(cleaned);
679
- return parsed;
680
- }
681
-
682
- // src/io/huggingface/languages-map.ts
683
- var languagesMap = {
684
- "en-US": "eng_Latn",
685
- "en-GB": "eng_Latn",
686
- "pt-BR": "por_Latn",
687
- "pt-PT": "por_Latn",
688
- "es-ES": "spa_Latn",
689
- "es-MX": "spa_Latn",
690
- "fr-FR": "fra_Latn",
691
- "fr-CA": "fra_Latn",
692
- "de-DE": "deu_Latn",
693
- "it-IT": "ita_Latn",
694
- "nl-NL": "nld_Latn",
695
- "pl-PL": "pol_Latn",
696
- "ru-RU": "rus_Cyrl",
697
- "uk-UA": "ukr_Cyrl",
698
- "bg-BG": "bul_Cyrl",
699
- "hr-HR": "hrv_Latn",
700
- "cs-CZ": "ces_Latn",
701
- "sk-SK": "slk_Latn",
702
- "hu-HU": "hun_Latn",
703
- "ro-RO": "ron_Latn",
704
- "fi-FI": "fin_Latn",
705
- "sv-SE": "swe_Latn",
706
- "da-DK": "dan_Latn",
707
- "no-NO": "nob_Latn",
708
- "is-IS": "isl_Latn",
709
- "et-EE": "est_Latn",
710
- "lv-LV": "lav_Latn",
711
- "lt-LT": "lit_Latn",
712
- "mt-MT": "mlt_Latn",
713
- "ga-IE": "gle_Latn",
714
- "cy-GB": "cym_Latn",
715
- "eu-ES": "eus_Latn",
716
- "ca-ES": "cat_Latn",
717
- "gl-ES": "glg_Latn",
718
- "oc-FR": "oci_Latn",
719
- "br-FR": "bre_Latn",
720
- "gd-GB": "gla_Latn",
721
- "kw-GB": "cor_Latn",
722
- "fur-IT": "fur_Latn",
723
- "rm-CH": "roh_Latn",
724
- "lb-LU": "ltz_Latn",
725
- "fy-NL": "fry_Latn",
726
- "af-ZA": "afr_Latn",
727
- "zh-CN": "zho_Hans",
728
- "zh-TW": "zho_Hant",
729
- "zh-HK": "zho_Hant",
730
- "ja-JP": "jpn_Jpan",
731
- "ko-KR": "kor_Hang",
732
- "th-TH": "tha_Thai",
733
- "vi-VN": "vie_Latn",
734
- "id-ID": "ind_Latn",
735
- "ms-MY": "zsm_Latn",
736
- "tl-PH": "tgl_Latn",
737
- "my-MM": "mya_Mymr",
738
- "km-KH": "khm_Khmr",
739
- "lo-LA": "lao_Laoo",
740
- "bn-BD": "ben_Beng",
741
- "bn-IN": "ben_Beng",
742
- "hi-IN": "hin_Deva",
743
- "ur-PK": "urd_Arab",
744
- "ur-IN": "urd_Arab",
745
- "pa-IN": "pan_Guru",
746
- "gu-IN": "guj_Gujr",
747
- "or-IN": "ory_Orya",
748
- "as-IN": "asm_Beng",
749
- "ml-IN": "mal_Mlym",
750
- "ta-IN": "tam_Tamil",
751
- "te-IN": "tel_Telu",
752
- "kn-IN": "kan_Knda",
753
- "si-LK": "sin_Sinh",
754
- "ne-NP": "nep_Deva",
755
- "dz-BT": "dzo_Tibt",
756
- "bo-CN": "bod_Tibt",
757
- "mn-MN": "khk_Cyrl",
758
- "ka-GE": "kat_Geor",
759
- "hy-AM": "hye_Armn",
760
- "az-AZ": "azj_Latn",
761
- "tr-TR": "tur_Latn",
762
- "fa-IR": "pes_Arab",
763
- "fa-AF": "pes_Arab",
764
- "ps-AF": "pbt_Arab",
765
- "ku-TR": "kmr_Latn",
766
- "he-IL": "heb_Hebr",
767
- "ar-SA": "arb_Arab",
768
- "ar-EG": "arb_Arab",
769
- "ar-MA": "arb_Arab",
770
- "ar-DZ": "arb_Arab",
771
- "ar-TN": "arb_Arab",
772
- "ar-LY": "arb_Arab",
773
- "ar-SD": "arb_Arab",
774
- "ar-IQ": "arb_Arab",
775
- "ar-SY": "arb_Arab",
776
- "ar-JO": "arb_Arab",
777
- "ar-LB": "arb_Arab",
778
- "ar-KW": "arb_Arab",
779
- "ar-AE": "arb_Arab",
780
- "ar-QA": "arb_Arab",
781
- "ar-BH": "arb_Arab",
782
- "ar-OM": "arb_Arab",
783
- "ar-YE": "arb_Arab",
784
- "ar-SO": "arb_Arab",
785
- "ar-DJ": "arb_Arab",
786
- "ar-KM": "arb_Arab",
787
- "ar-TD": "arb_Arab",
788
- "ar-ER": "arb_Arab",
789
- "ar-IL": "arb_Arab",
790
- "ar-PS": "arb_Arab",
791
- "ar-001": "arb_Arab",
792
- "sw-KE": "swh_Latn",
793
- "sw-TZ": "swh_Latn",
794
- "am-ET": "amh_Ethi",
795
- "om-ET": "gaz_Latn",
796
- "so-SO": "som_Latn",
797
- "ha-NG": "hau_Latn",
798
- "yo-NG": "yor_Latn",
799
- "ig-NG": "ibo_Latn",
800
- "zu-ZA": "zul_Latn",
801
- "xh-ZA": "xho_Latn",
802
- "rw-RW": "kin_Latn",
803
- "lg-UG": "lug_Latn",
804
- "ak-GH": "aka_Latn",
805
- "tw-GH": "twi_Latn",
806
- "ee-GH": "ewe_Latn",
807
- "ff-SN": "fuv_Latn",
808
- "wo-SN": "wol_Latn",
809
- "sn-ZW": "sna_Latn",
810
- "nd-ZW": "nde_Latn",
811
- "ny-MW": "nya_Latn",
812
- "st-ZA": "sot_Latn",
813
- "tn-BW": "tsn_Latn",
814
- "ts-ZA": "tso_Latn",
815
- "ve-ZA": "ven_Latn",
816
- "ss-ZA": "ssw_Latn",
817
- "nr-ZA": "nbl_Latn",
818
- "qu-PE": "quy_Latn",
819
- "qu-BO": "quy_Latn",
820
- "qu-EC": "quy_Latn",
821
- "ay-BO": "aym_Latn",
822
- "gn-PY": "grn_Latn",
823
- "ht-HT": "hat_Latn",
824
- "jv-ID": "jav_Latn",
825
- "su-ID": "sun_Latn",
826
- "ceb-PH": "ceb_Latn",
827
- "ilo-PH": "ilo_Latn",
828
- "war-PH": "war_Latn",
829
- "bjn-ID": "bjn_Latn",
830
- "ban-ID": "ban_Latn",
831
- "mad-ID": "mad_Latn",
832
- "min-ID": "min_Latn",
833
- "ace-ID": "ace_Latn",
834
- "bug-ID": "bug_Latn",
835
- "gor-ID": "gor_Latn",
836
- "mak-ID": "mak_Latn",
837
- "mdr-ID": "mdr_Latn",
838
- "sas-ID": "sas_Latn",
839
- "shn-MM": "shn_Mymr",
840
- "kac-MM": "kac_Latn",
841
- "lzh-CN": "lzh_Hant",
842
- "wuu-CN": "wuu_Hans",
843
- "yue-CN": "yue_Hant",
844
- "nan-TW": "nan_Hant",
845
- "hak-TW": "hak_Hant",
846
- "cjy-CN": "cjy_Hans",
847
- "cmn-CN": "cmn_Hans",
848
- "cmn-TW": "cmn_Hant",
849
- "cmn-SG": "cmn_Hans",
850
- "cmn-HK": "cmn_Hant",
851
- "cmn-MO": "cmn_Hant",
852
- "cmn-001": "cmn_Hans",
853
- "haw-US": "haw_Latn",
854
- "mi-NZ": "mri_Latn",
855
- "sm-WS": "smo_Latn",
856
- "to-TO": "ton_Latn",
857
- "fj-FJ": "fij_Latn",
858
- "ty-PF": "tah_Latn",
859
- "co-FR": "cos_Latn",
860
- "eu-FR": "eus_Latn",
861
- "kk-KZ": "kaz_Cyrl",
862
- "ky-KG": "kir_Cyrl",
863
- "uz-UZ": "uzn_Latn",
864
- "tg-TJ": "tgk_Cyrl",
865
- "tk-TM": "tuk_Latn"
866
- };
867
-
868
- // src/io/huggingface/ask.ts
869
- function getLanguageCode(language) {
870
- return languagesMap[language];
871
- }
872
- function progressCallback(progress) {
873
- process.stdout.clearLine(0);
874
- process.stdout.cursorTo(0);
875
- if (progress.status === "download") {
876
- process.stdout.write("Downloading...");
877
- } else if (progress.status === "initiate") {
878
- process.stdout.write("Initializing...");
879
- } else if (progress.status === "done") {
880
- process.stdout.write("Done!");
881
- } else if (progress.status === "progress" && "progress" in progress && "loaded" in progress && "total" in progress) {
882
- process.stdout.write(
883
- `Downloading: ${Number(progress.progress).toFixed(2)}%, loaded: ${progress.loaded}/${progress.total}`
884
- );
885
- }
886
- }
887
- async function pipeLanguage(pipe, original, srcLanguage, targetLanguage) {
888
- const response = await pipe(original, {
889
- src_lang: srcLanguage,
890
- tgt_lang: targetLanguage,
891
- temperature: 1
554
+ ${postPrompt2}`.trim();
555
+ const messages = [new Message("user", fullPrompt)];
556
+ const model = config.llm.model ?? "gpt-4o-mini";
557
+ const response = await engine.complete(engine.buildModel(model), messages, {
558
+ temperature: config.llm.temperature
892
559
  });
893
- return response;
894
- }
895
- async function askHuggingface(original) {
896
- const config = await awaitedConfig;
897
- const cacheDir = `${config.cache.dir}/.cache`;
898
- env.cacheDir = cacheDir;
899
- const pipe = await pipeline("translation", config.llm.model, {
900
- progress_callback: progressCallback,
901
- cache_dir: cacheDir
902
- });
903
- const { languages } = config;
904
- let responses = [];
905
- for await (const language of languages) {
906
- const response = await pipeLanguage(
907
- pipe,
908
- original,
909
- getLanguageCode(config.sourceLanguage),
910
- getLanguageCode(language)
911
- );
912
- if (Array.isArray(response)) {
913
- responses = responses.concat(
914
- response.map((r) => ({
915
- ...r,
916
- targetLanguage: language
917
- }))
918
- );
919
- } else {
920
- responses.push({
921
- ...response,
922
- targetLanguage: language
923
- });
924
- }
925
- }
926
- return { responses, original };
927
- }
928
-
929
- // src/io/huggingface/commit-response.ts
930
- function commitResponseHuggingface(response) {
931
- const { responses, original } = response;
932
- const translation = responses.reduce((acc, curr) => {
933
- acc[curr.targetLanguage] = curr.translation_text;
934
- return acc;
935
- }, {});
936
- return {
937
- translation,
938
- original
939
- };
940
- }
941
-
942
- // src/io/huggingface/parse.ts
943
- function parseHuggingface(unparsed) {
944
- if (typeof unparsed === "string") {
945
- throw new Error("CommitResponse should not be a string here.");
946
- }
947
- return unparsed;
948
- }
949
-
950
- // src/io/ask-llm.ts
951
- var llmChoices = {
952
- anthropic: {
953
- ask: askAnthropic,
954
- commitResponse: commitResponseAnthropic,
955
- parse: parseAnthropic
956
- },
957
- gemini: {
958
- ask: askGemini,
959
- commitResponse: commitResponseGemini,
960
- parse: parseGemini
961
- },
962
- huggingface: {
963
- ask: askHuggingface,
964
- commitResponse: commitResponseHuggingface,
965
- parse: parseHuggingface
560
+ if (config.debug) {
561
+ console.log("LLM response:", JSON.stringify({ provider, model: config.llm.model, response: response.content }));
966
562
  }
967
- };
968
- async function processLLMChoice(llmChoice, prompt, prePrompt2, postPrompt2) {
969
- const response = await llmChoice.ask(prompt, prePrompt2, postPrompt2);
970
- const unparsed = llmChoice.commitResponse(response);
971
- const parsed = llmChoice.parse(unparsed);
972
- return parsed;
973
- }
974
- async function askLLM(prompt, prePrompt2, postPrompt2) {
975
- const config = await awaitedConfig;
976
- const llmChoiceName = config.llm.choice;
977
- const llmChoice = llmChoices[llmChoiceName];
978
- if (!llmChoice) {
979
- throw new Error("LLMChoice not found");
563
+ if (!response.content) {
564
+ throw new Error("LLM response content is empty");
980
565
  }
981
- return processLLMChoice(llmChoice, prompt, prePrompt2, postPrompt2);
566
+ return parseResponse(response.content);
982
567
  }
983
568
 
984
569
  // src/gringow.ts
@@ -996,6 +581,10 @@ async function rebuild(cacheId) {
996
581
  const cached = await checkCache(cacheId);
997
582
  if (!cached) throw new Error("Cache item not found");
998
583
  const { prepend, append } = getPrependAndAppend(config, cached);
584
+ if (config.debug) {
585
+ console.log(`rebuild::prepend ${cacheId}:`, { prepend });
586
+ console.log(`rebuild::append ${cacheId}:`, { append });
587
+ }
999
588
  const translation = await askLLM(cached.original, prepend, append);
1000
589
  const output = {
1001
590
  ...translation,
@@ -1021,6 +610,10 @@ async function Gringow(strings, ...values) {
1021
610
  return { cacheId, translation: cached };
1022
611
  }
1023
612
  const { prepend, append } = getPrependAndAppend(config, cached);
613
+ if (config.debug) {
614
+ console.log(`asking::prepend ${cacheId}:`, { prepend });
615
+ console.log(`asking::append ${cacheId}:`, { append });
616
+ }
1024
617
  const translation = await askLLM(flatten, prepend, append);
1025
618
  const output = {
1026
619
  ...translation,