utilitas 1998.2.18 → 1998.2.20

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/lib/alan.mjs CHANGED
@@ -1,37 +1,42 @@
1
+ import { fileTypeFromBuffer } from 'file-type';
2
+ import { end, loop } from './event.mjs';
3
+ import { createWavHeader } from './media.mjs';
1
4
  import { BASE64, BUFFER, DATAURL, MIME_BINARY, STREAM, convert } from './storage.mjs';
2
5
  import { create as createUoid } from './uoid.mjs';
3
- import { createWavHeader } from './media.mjs';
4
- import { end, loop } from './event.mjs';
5
- import { fileTypeFromBuffer } from 'file-type';
6
6
 
7
7
  import {
8
+ log as _log,
9
+ renderText as _renderText,
8
10
  base64Encode, ensureArray, ensureString, extract, ignoreErrFunc,
9
- log as _log, need, parseJson, renderText as _renderText, throwError,
11
+ need, parseJson,
12
+ throwError,
10
13
  } from './utilitas.mjs';
11
14
 
12
15
  const _NEED = [
13
- '@anthropic-ai/sdk', '@google/generative-ai', 'js-tiktoken', 'ollama',
14
- 'OpenAI',
16
+ '@anthropic-ai/sdk', '@anthropic-ai/vertex-sdk', '@google/generative-ai',
17
+ 'js-tiktoken', 'ollama', 'OpenAI',
15
18
  ];
16
19
 
17
20
  const [
18
21
  OPENAI, GEMINI, CHATGPT, OPENAI_EMBEDDING, GEMINI_EMEDDING, OPENAI_TRAINING,
19
22
  OLLAMA, CLAUDE, GPT_4O_MINI, GPT_4O, GPT_O1, GPT_O3_MINI, GEMINI_20_FLASH,
20
23
  GEMINI_20_FLASH_THINKING, GEMINI_20_PRO, NOVA, EMBEDDING_001, DEEPSEEK_R1,
21
- DEEPSEEK_R1_32B, MD_CODE, CHATGPT_REASONING, TEXT_EMBEDDING_3_SMALL,
22
- TEXT_EMBEDDING_3_LARGE, CLAUDE_35_SONNET, CLAUDE_35_HAIKU, AUDIO, WAV,
23
- CHATGPT_MINI, ATTACHMENTS, CHAT, OPENAI_VOICE, MEDIUM, LOW, HIGH,
24
- GPT_REASONING_EFFORT, THINK, THINK_STR, THINK_END,
24
+ DEEPSEEK_R1_32B, DEEPSEEK_R1_70B, MD_CODE, CHATGPT_REASONING,
25
+ TEXT_EMBEDDING_3_SMALL, TEXT_EMBEDDING_3_LARGE, CLAUDE_35_SONNET,
26
+ CLAUDE_35_HAIKU, CLOUD_37_SONNET, AUDIO, WAV, CHATGPT_MINI, ATTACHMENTS,
27
+ CHAT, OPENAI_VOICE, MEDIUM, LOW, HIGH, GPT_REASONING_EFFORT, THINK,
28
+ THINK_STR, THINK_END, AZURE,
25
29
  ] = [
26
30
  'OPENAI', 'GEMINI', 'CHATGPT', 'OPENAI_EMBEDDING', 'GEMINI_EMEDDING',
27
31
  'OPENAI_TRAINING', 'OLLAMA', 'CLAUDE', 'gpt-4o-mini', 'gpt-4o', 'o1',
28
32
  'o3-mini', 'gemini-2.0-flash', 'gemini-2.0-flash-thinking-exp',
29
33
  'gemini-2.0-pro-exp', 'nova', 'embedding-001', 'deepseek-r1',
30
- 'deepseek-r1:32b', '```', 'CHATGPT_REASONING', 'text-embedding-3-small',
31
- 'text-embedding-3-large', 'claude-3-5-sonnet-latest',
32
- 'claude-3-5-haiku-latest', 'audio', 'wav', 'CHATGPT_MINI',
34
+ 'deepseek-r1:32b', 'deepseek-r1:70b', '```', 'CHATGPT_REASONING',
35
+ 'text-embedding-3-small', 'text-embedding-3-large',
36
+ 'claude-3-5-sonnet-latest', 'claude-3-5-haiku-latest',
37
+ 'claude-3-7-sonnet@20250219', 'audio', 'wav', 'CHATGPT_MINI',
33
38
  '[ATTACHMENTS]', 'CHAT', 'OPENAI_VOICE', 'medium', 'low', 'high',
34
- 'medium', 'think', '<think>', '</think>',
39
+ 'medium', 'think', '<think>', '</think>', 'AZURE',
35
40
  ];
36
41
 
37
42
  const [
@@ -81,10 +86,11 @@ const DEFAULT_MODELS = {
81
86
  [CHATGPT_MINI]: GPT_4O_MINI,
82
87
  [CHATGPT_REASONING]: GPT_O3_MINI,
83
88
  [CHATGPT]: GPT_4O,
84
- [CLAUDE]: CLAUDE_35_SONNET,
89
+ [CLAUDE]: CLOUD_37_SONNET,
85
90
  [GEMINI_EMEDDING]: EMBEDDING_001,
86
91
  [GEMINI]: GEMINI_20_FLASH,
87
92
  [OLLAMA]: DEEPSEEK_R1,
93
+ [AZURE]: DEEPSEEK_R1,
88
94
  [OPENAI_EMBEDDING]: TEXT_EMBEDDING_3_SMALL,
89
95
  [OPENAI_TRAINING]: GPT_4O_MINI, // https://platform.openai.com/docs/guides/fine-tuning
90
96
  [OPENAI_VOICE]: NOVA,
@@ -252,7 +258,7 @@ const MODELS = {
252
258
  ],
253
259
  },
254
260
  [DEEPSEEK_R1]: {
255
- contextWindow: 128000,
261
+ contextWindow: 128 * 1000,
256
262
  maxOutputTokens: 32768,
257
263
  requestLimitsRPM: Infinity,
258
264
  tokenLimitsTPM: Infinity,
@@ -298,10 +304,30 @@ const MODELS = {
298
304
  png, jpeg, gif, webp, pdf,
299
305
  ],
300
306
  },
307
+ // https://console.cloud.google.com/vertex-ai/publishers/anthropic/model-garden/claude-3-7-sonnet?authuser=5&inv=1&invt=Abqftg&project=backend-alpha-97077
308
+ [CLOUD_37_SONNET]: {
309
+ contextWindow: 200 * 1000,
310
+ maxOutputTokens: 64 * 1000, // Should be 128 * 1000, but Anthropic SDK limits it to 64 * 1000
311
+ imageCostTokens: size8k / 750,
312
+ documentCostTokens: 3000 * 100, // 100 pages: https://docs.anthropic.com/en/docs/build-with-claude/pdf-support
313
+ maxImagePerPrompt: 5, // https://docs.anthropic.com/en/docs/build-with-claude/vision
314
+ maxImageSize: 1092, // by pixels
315
+ maxDocumentPages: 100,
316
+ maxDocumentFile: 1024 * 1024 * 32, // 32MB
317
+ requestLimitsRPM: 50,
318
+ tokenLimitsITPM: 40000,
319
+ tokenLimitsOTPM: 8000,
320
+ trainingData: 'Apr 2024', // ?
321
+ reasoning: true,
322
+ supportedMimeTypes: [
323
+ png, jpeg, gif, webp, pdf,
324
+ ],
325
+ },
301
326
  };
302
327
 
303
328
  MODELS[CLAUDE_35_HAIKU] = MODELS[CLAUDE_35_SONNET];
304
329
  MODELS[DEEPSEEK_R1_32B] = MODELS[DEEPSEEK_R1];
330
+ MODELS[DEEPSEEK_R1_70B] = MODELS[DEEPSEEK_R1];
305
331
 
306
332
  for (const n in MODELS) {
307
333
  MODELS[n]['name'] = n;
@@ -340,10 +366,14 @@ const unifyType = (type, name) => {
340
366
  const init = async (options) => {
341
367
  const provider = unifyProvider(options);
342
368
  switch (provider) {
343
- case OPENAI:
369
+ case OPENAI: case AZURE:
344
370
  if (options?.apiKey) {
345
- const OpenAI = await need('openai');
346
- const openai = new OpenAI(options);
371
+ provider === AZURE && assert(
372
+ options?.baseURL, 'Azure api endpoint is required.'
373
+ );
374
+ const libOpenAI = await need('openai', { raw: true });
375
+ const openai = new (options?.endpoint && options?.deployment
376
+ ? libOpenAI.AzureOpenAI : libOpenAI.OpenAI)(options);
347
377
  clients[provider] = { client: openai, clientBeta: openai.beta };
348
378
  }
349
379
  break;
@@ -373,9 +403,20 @@ const init = async (options) => {
373
403
  }
374
404
  break;
375
405
  case CLAUDE:
376
- if (options?.apiKey) {
377
- const Anthropic = await need('@anthropic-ai/sdk');
378
- const anthropic = new Anthropic({ apiKey: options?.apiKey });
406
+ if (options?.apiKey || (options?.credentials && options?.projectId)) {
407
+ // https://github.com/anthropics/anthropic-sdk-typescript/tree/main/packages/vertex-sdk
408
+ const Anthropic = (await need(options?.credentials
409
+ ? '@anthropic-ai/vertex-sdk' : '@anthropic-ai/sdk', { raw: true }))[
410
+ options?.credentials ? 'AnthropicVertex' : 'Anthropic'
411
+ ];
412
+ if (options?.credentials) {
413
+ process.env['GOOGLE_APPLICATION_CREDENTIALS'] = options.credentials;
414
+ process.env['ANTHROPIC_VERTEX_PROJECT_ID'] = options.projectId;
415
+ }
416
+ const anthropic = new Anthropic({
417
+ ...options?.apiKey ? { apiKey: options.apiKey } : {},
418
+ ...options?.credentials ? { region: options?.region || 'us-east5' } : {},
419
+ });
379
420
  clients[provider] = { client: anthropic };
380
421
  }
381
422
  break;
@@ -611,7 +652,9 @@ const promptChatGPT = async (content, options = {}) => {
611
652
  // Structured Outputs: https://openai.com/index/introducing-structured-outputs-in-the-api/
612
653
  client.baseURL !== OPENAI_BASE_URL
613
654
  && options?.attachments?.length && (options.attachments = []);
614
- if (options?.model) { } else if (options?.reasoning) {
655
+ if (options?.model) { } else if (options?.provider === AZURE) {
656
+ options.model = DEFAULT_MODELS[AZURE];
657
+ } else if (options?.reasoning) {
615
658
  options.model = DEFAULT_MODELS[CHATGPT_REASONING];
616
659
  } else {
617
660
  options.model = DEFAULT_MODELS[CHATGPT];
@@ -671,6 +714,10 @@ const promptChatGPT = async (content, options = {}) => {
671
714
  return await packGptResp(chunk, options);
672
715
  };
673
716
 
717
+ const promptAzure = async (content, options = {}) => await promptChatGPT(
718
+ content, { ...options, provider: AZURE }
719
+ );
720
+
674
721
  const promptOllama = async (content, options = {}) => {
675
722
  const { client, model } = await getOllamaClient(options);
676
723
  // https://github.com/ollama/ollama-js
@@ -697,16 +744,27 @@ const promptOllama = async (content, options = {}) => {
697
744
  const promptClaude = async (content, options = {}) => {
698
745
  const { client } = await getClaudeClient(options);
699
746
  options.model = options?.model || DEFAULT_MODELS[CLAUDE];
747
+ const reasoning = options?.reasoning ?? MODELS[options.model]?.reasoning;
700
748
  const resp = await client.messages.create({
701
749
  model: options.model, max_tokens: MODELS[options.model].maxOutputTokens,
702
750
  messages: [
703
751
  ...options?.messages || [], buildClaudeMessage(content, options)
704
- ], stream: !!options?.stream,
752
+ ], stream: !!options?.stream, ...reasoning ? {
753
+ thinking: options?.thinking || { type: 'enabled', budget_tokens: 1024 },
754
+ } : {} // https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking
705
755
  });
706
- let [event, result] = [null, ''];
756
+ let [event, result, thinkEnd] = [null, '', ''];
707
757
  if (options?.stream) {
708
758
  for await (event of resp) {
709
- const delta = event?.content_block?.text || event?.delta?.text || '';
759
+ let [thkDelta, txtDelta] = [
760
+ event?.content_block?.thinking || event?.delta?.thinking || '',
761
+ event?.content_block?.text || event?.delta?.text || '',
762
+ ];
763
+ if (reasoning) {
764
+ !result && thkDelta && (thkDelta = `${THINK_STR}\n${thkDelta}`);
765
+ result && txtDelta && !thinkEnd && (thinkEnd = thkDelta = `${thkDelta}\n${THINK_END}\n\n`);
766
+ }
767
+ const delta = thkDelta + txtDelta;
710
768
  if (delta === '') { continue; }
711
769
  result += delta;
712
770
  event.content = { text: options?.delta ? delta : result };
@@ -806,7 +864,7 @@ const promptGemini = async (content, options) => {
806
864
  // Google's bug: history is not allowed while using inline_data?
807
865
  assert(!(
808
866
  options?.jsonMode && MODELS[genModel]?.json == false
809
- ), `This model does not support JSON output: ${genModel}`);
867
+ ), `This model does not support JSON output: ${genModel} `);
810
868
  const chat = generative.startChat({
811
869
  history: options?.messages && !options?.attachments?.length
812
870
  ? options.messages : [],
@@ -902,7 +960,7 @@ const listGptFineTuningEvents = async (job_id, options) => {
902
960
 
903
961
  const tailGptFineTuningEvents = async (job_id, options) => {
904
962
  assert(job_id, 'Job ID is required.');
905
- const [loopName, listOpts] = [`GPT-${job_id}`, {
963
+ const [loopName, listOpts] = [`GPT - ${job_id} `, {
906
964
  ...options, params: { ...options?.params, order: 'ascending' }
907
965
  }];
908
966
  let lastEvent;
@@ -939,7 +997,6 @@ const initChat = async (options) => {
939
997
  assert(model, `Invalid chat model: '${i}'.`);
940
998
  chatConfig.engines[key] = options.engines[i];
941
999
  chatConfig.engines[key].model = chatConfig.engines[key].model || model;
942
- print(chatConfig.engines[key].model);
943
1000
  const mxPmpt = MODELS[chatConfig.engines[key].model].maxInputTokens / 2;
944
1001
  const pmptTokens = await countTokens([buildGeminiHistory(
945
1002
  chatConfig.systemPrompt, { role: system }
@@ -1006,7 +1063,7 @@ const talk = async (input, options) => {
1006
1063
  const session = await getSession(sessionId, { engine, ...options });
1007
1064
  let [resp, sys, messages, msgBuilder] = [null, [], [], null];
1008
1065
  switch (engine) {
1009
- case CHATGPT:
1066
+ case CHATGPT: case AZURE:
1010
1067
  sys.push(buildGptMessage(session.systemPrompt, { role: system }));
1011
1068
  msgBuilder = () => {
1012
1069
  messages = [];
@@ -1088,6 +1145,9 @@ const talk = async (input, options) => {
1088
1145
  case OLLAMA:
1089
1146
  resp = await promptOllama(input, { messages, model, ...options });
1090
1147
  break;
1148
+ case AZURE:
1149
+ resp = await promptAzure(input, { messages, model, ...options });
1150
+ break;
1091
1151
  }
1092
1152
  chat.response = resp.text;
1093
1153
  chat?.request && chat?.response && session.messages.push(chat);
@@ -1208,39 +1268,27 @@ const analyzeSessions = async (sessionIds, options) => {
1208
1268
  };
1209
1269
 
1210
1270
  const PREFERRED_ENGINES = [
1211
- { client: OPENAI, func: promptChatGPT, multimodal: 1 },
1212
- { client: GEMINI, func: promptGemini, multimodal: 0 },
1271
+ { client: OPENAI, func: promptChatGPT, multimodal: 0 },
1272
+ { client: GEMINI, func: promptGemini, multimodal: 1 },
1213
1273
  { client: CLAUDE, func: promptClaude, multimodal: 2 },
1274
+ { client: AZURE, func: promptAzure, multimodal: 3 },
1214
1275
  { client: OLLAMA, func: promptOllama, multimodal: 99 },
1215
1276
  ]; // keep gpt first to avoid gemini grounding by default
1216
1277
 
1217
1278
  export default init;
1218
1279
  export {
1219
- _NEED,
1220
- ATTACHMENT_TOKEN_COST,
1221
- CODE_INTERPRETER,
1222
- DEFAULT_MODELS,
1280
+ ATTACHMENT_TOKEN_COST, CLOUD_37_SONNET, CODE_INTERPRETER, DEEPSEEK_R1,
1281
+ DEEPSEEK_R1_32B, DEEPSEEK_R1_70B, DEFAULT_MODELS,
1223
1282
  EMBEDDING_001,
1224
- FUNCTION,
1225
- GEMINI_20_FLASH_THINKING,
1226
- GEMINI_20_FLASH,
1227
- GPT_4O_MINI,
1228
- GPT_4O,
1229
- GPT_O3_MINI,
1230
- GPT_O1,
1231
- DEEPSEEK_R1,
1232
- DEEPSEEK_R1_32B,
1233
- MODELS,
1283
+ FUNCTION, GEMINI_20_FLASH, GEMINI_20_FLASH_THINKING, GPT_4O, GPT_4O_MINI, GPT_O1, GPT_O3_MINI, MODELS,
1234
1284
  OPENAI_VOICE,
1235
1285
  RETRIEVAL,
1236
- TEXT_EMBEDDING_3_SMALL,
1237
- analyzeSessions,
1286
+ TEXT_EMBEDDING_3_SMALL, _NEED, analyzeSessions,
1238
1287
  buildGptTrainingCase,
1239
1288
  buildGptTrainingCases,
1240
1289
  cancelGptFineTuningJob,
1241
1290
  countTokens,
1242
- createGeminiEmbedding,
1243
- createGptFineTuningJob,
1291
+ createGeminiEmbedding, createGptFineTuningJob,
1244
1292
  createOpenAIEmbedding,
1245
1293
  deleteFile,
1246
1294
  distillFile,
@@ -1255,8 +1303,7 @@ export {
1255
1303
  listGptFineTuningJobs,
1256
1304
  listOpenAIModels,
1257
1305
  ogg,
1258
- prompt,
1259
- promptChatGPT,
1306
+ prompt, promptAzure, promptChatGPT,
1260
1307
  promptClaude,
1261
1308
  promptGemini,
1262
1309
  promptOllama,
@@ -1266,5 +1313,5 @@ export {
1266
1313
  trimPrompt,
1267
1314
  uploadFile,
1268
1315
  uploadFileForFineTuning,
1269
- wav,
1316
+ wav
1270
1317
  };
package/lib/manifest.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  const manifest = {
2
2
  "name": "utilitas",
3
3
  "description": "Just another common utility for JavaScript.",
4
- "version": "1998.2.18",
4
+ "version": "1998.2.20",
5
5
  "private": false,
6
6
  "homepage": "https://github.com/Leask/utilitas",
7
7
  "main": "index.mjs",
@@ -25,6 +25,7 @@ const manifest = {
25
25
  },
26
26
  "devDependencies": {
27
27
  "@anthropic-ai/sdk": "^0.36.3",
28
+ "@anthropic-ai/vertex-sdk": "^0.7.0",
28
29
  "@ffmpeg-installer/ffmpeg": "^1.1.0",
29
30
  "@ffprobe-installer/ffprobe": "^2.1.2",
30
31
  "@google-cloud/speech": "^6.7.0",
package/lib/storage.mjs CHANGED
@@ -1,16 +1,17 @@
1
1
  import {
2
+ log as _log,
2
3
  base64Decode, base64Encode, ensureString, extract, ignoreErrFunc,
3
- log as _log, mergeAtoB, need, throwError, trim, voidFunc, which,
4
+ mergeAtoB, need, throwError, trim, voidFunc, which,
4
5
  } from './utilitas.mjs';
5
6
 
6
- import { basename, extname, join } from 'path';
7
- import { constants as consts, createReadStream, promises as fs, readSync } from 'fs';
8
- import { defaultAlgorithm, hash } from './encryption.mjs';
9
- import { deflate as __zip, unzip as __unzip } from 'zlib';
10
7
  import { fileTypeFromBuffer } from 'file-type';
8
+ import { constants as consts, createReadStream, promises as fs, readSync } from 'fs';
11
9
  import { homedir, tmpdir } from 'os';
10
+ import { basename, extname, join } from 'path';
12
11
  import { promisify } from 'util';
13
12
  import { v4 as uuidv4 } from 'uuid';
13
+ import { unzip as __unzip, deflate as __zip } from 'zlib';
14
+ import { defaultAlgorithm, hash } from './encryption.mjs';
14
15
 
15
16
  const _NEED = ['file-type', 'mime-types', '@google-cloud/storage'];
16
17
  const errorMessage = 'Invalid file.';
@@ -467,26 +468,15 @@ const deleteOnCloud = async (path, options) => {
467
468
  };
468
469
 
469
470
  export {
470
- _NEED,
471
- BASE64,
472
- BUFFER,
473
- DATAURL,
474
- FILE,
475
- MIME_BINARY,
476
- STREAM,
477
- analyzeFile,
478
- assertPath,
479
- blobToBuffer,
480
- convert,
481
- decodeBase64DataURL,
471
+ _NEED, analyzeFile,
472
+ assertPath, BASE64, blobToBuffer, BUFFER, convert, DATAURL, decodeBase64DataURL,
482
473
  deleteFileOnCloud,
483
474
  deleteOnCloud,
484
475
  downloadFileFromCloud,
485
476
  downloadFromCloud,
486
477
  encodeBase64DataURL,
487
478
  exists,
488
- existsOnCloud,
489
- getConfig,
479
+ existsOnCloud, FILE, getConfig,
490
480
  getConfigFilename,
491
481
  getGcUrlByBucket,
492
482
  getIdByGs,
@@ -497,18 +487,16 @@ export {
497
487
  legalFilename,
498
488
  lsOnCloud,
499
489
  mapFilename,
500
- mergeFile,
501
- readFile,
490
+ mergeFile, MIME_BINARY, readFile,
502
491
  readJson,
503
492
  sanitizeFilename,
504
493
  setConfig,
505
- sliceFile,
506
- touchPath,
494
+ sliceFile, STREAM, touchPath,
507
495
  tryRm,
508
496
  unzip,
509
497
  uploadToCloud,
510
498
  writeFile,
511
499
  writeJson,
512
500
  writeTempFile,
513
- zip,
501
+ zip
514
502
  };
package/lib/vision.mjs CHANGED
@@ -3,14 +3,16 @@ import {
3
3
  } from './storage.mjs';
4
4
 
5
5
  import {
6
- ensureArray, ensureString, ignoreErrFunc, log as _log, need, throwError,
6
+ log as _log,
7
+ ensureArray, ensureString, ignoreErrFunc,
8
+ need, throwError,
7
9
  trim,
8
10
  } from './utilitas.mjs';
9
11
 
10
- import { v4 as uuidv4 } from 'uuid';
11
- import { getApiKeyCredentials } from './encryption.mjs';
12
12
  import fs from 'node:fs';
13
13
  import path from 'node:path';
14
+ import { v4 as uuidv4 } from 'uuid';
15
+ import { getApiKeyCredentials } from './encryption.mjs';
14
16
 
15
17
  const _NEED = [
16
18
  '@google-cloud/vision', 'office-text-extractor', 'pdfjs-dist',
@@ -268,5 +270,5 @@ export {
268
270
  parseOfficeFile,
269
271
  read,
270
272
  readAll,
271
- see,
273
+ see
272
274
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "utilitas",
3
3
  "description": "Just another common utility for JavaScript.",
4
- "version": "1998.2.18",
4
+ "version": "1998.2.20",
5
5
  "private": false,
6
6
  "homepage": "https://github.com/Leask/utilitas",
7
7
  "main": "index.mjs",
@@ -36,6 +36,7 @@
36
36
  },
37
37
  "devDependencies": {
38
38
  "@anthropic-ai/sdk": "^0.36.3",
39
+ "@anthropic-ai/vertex-sdk": "^0.7.0",
39
40
  "@ffmpeg-installer/ffmpeg": "^1.1.0",
40
41
  "@ffprobe-installer/ffprobe": "^2.1.2",
41
42
  "@google-cloud/speech": "^6.7.0",