@gringow/gringow 0.1.4 → 0.2.1

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