viho-llm 1.0.9 → 1.1.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.
package/index.js CHANGED
@@ -4,9 +4,11 @@ var genai = require('@google/genai');
4
4
  var mime = require('mime-types');
5
5
  var qiao_log_js = require('qiao.log.js');
6
6
  var OpenAI = require('openai');
7
+ var crypto = require('crypto');
8
+ var https = require('https');
7
9
 
8
10
  // gemini
9
- const logger$4 = qiao_log_js.Logger('gemini-util.js');
11
+ const logger$6 = qiao_log_js.Logger('gemini-util.js');
10
12
 
11
13
  /**
12
14
  * chat
@@ -20,19 +22,19 @@ const chat$1 = async (client, modelName, chatOptions) => {
20
22
 
21
23
  // check
22
24
  if (!client) {
23
- logger$4.error(methodName, 'need client');
25
+ logger$6.error(methodName, 'need client');
24
26
  return;
25
27
  }
26
28
  if (!modelName) {
27
- logger$4.error(methodName, 'need modelName');
29
+ logger$6.error(methodName, 'need modelName');
28
30
  return;
29
31
  }
30
32
  if (!chatOptions) {
31
- logger$4.error(methodName, 'need chatOptions');
33
+ logger$6.error(methodName, 'need chatOptions');
32
34
  return;
33
35
  }
34
36
  if (!chatOptions.contents) {
35
- logger$4.error(methodName, 'need chatOptions.contents');
37
+ logger$6.error(methodName, 'need chatOptions.contents');
36
38
  return;
37
39
  }
38
40
 
@@ -48,13 +50,13 @@ const chat$1 = async (client, modelName, chatOptions) => {
48
50
  // gen
49
51
  const response = await client.models.generateContent(options);
50
52
  if (!response || !response.text) {
51
- logger$4.error(methodName, 'invalid response');
53
+ logger$6.error(methodName, 'invalid response');
52
54
  return;
53
55
  }
54
56
 
55
57
  return response.text;
56
58
  } catch (error) {
57
- logger$4.error(methodName, 'error', error);
59
+ logger$6.error(methodName, 'error', error);
58
60
  }
59
61
  };
60
62
 
@@ -71,23 +73,23 @@ const chatWithStreaming$1 = async (client, modelName, chatOptions, callbackOptio
71
73
 
72
74
  // check
73
75
  if (!client) {
74
- logger$4.error(methodName, 'need client');
76
+ logger$6.error(methodName, 'need client');
75
77
  return;
76
78
  }
77
79
  if (!modelName) {
78
- logger$4.error(methodName, 'need modelName');
80
+ logger$6.error(methodName, 'need modelName');
79
81
  return;
80
82
  }
81
83
  if (!chatOptions) {
82
- logger$4.error(methodName, 'need chatOptions');
84
+ logger$6.error(methodName, 'need chatOptions');
83
85
  return;
84
86
  }
85
87
  if (!chatOptions.contents) {
86
- logger$4.error(methodName, 'need chatOptions.contents');
88
+ logger$6.error(methodName, 'need chatOptions.contents');
87
89
  return;
88
90
  }
89
91
  if (!callbackOptions) {
90
- logger$4.error(methodName, 'need callbackOptions');
92
+ logger$6.error(methodName, 'need callbackOptions');
91
93
  return;
92
94
  }
93
95
 
@@ -145,38 +147,38 @@ const cacheAdd = async (client, modelName, cacheOptions) => {
145
147
 
146
148
  // check
147
149
  if (!client) {
148
- logger$4.error(methodName, 'need client');
150
+ logger$6.error(methodName, 'need client');
149
151
  return;
150
152
  }
151
153
  if (!modelName) {
152
- logger$4.error(methodName, 'need modelName');
154
+ logger$6.error(methodName, 'need modelName');
153
155
  return;
154
156
  }
155
157
  if (!cacheOptions) {
156
- logger$4.error(methodName, 'need cacheOptions');
158
+ logger$6.error(methodName, 'need cacheOptions');
157
159
  return;
158
160
  }
159
161
  if (!cacheOptions.gsPath) {
160
- logger$4.error(methodName, 'need cacheOptions.gsPath');
162
+ logger$6.error(methodName, 'need cacheOptions.gsPath');
161
163
  return;
162
164
  }
163
165
  if (!cacheOptions.systemPrompt) {
164
- logger$4.error(methodName, 'need cacheOptions.systemPrompt');
166
+ logger$6.error(methodName, 'need cacheOptions.systemPrompt');
165
167
  return;
166
168
  }
167
169
  if (!cacheOptions.cacheName) {
168
- logger$4.error(methodName, 'need cacheOptions.cacheName');
170
+ logger$6.error(methodName, 'need cacheOptions.cacheName');
169
171
  return;
170
172
  }
171
173
  if (!cacheOptions.cacheTTL) {
172
- logger$4.error(methodName, 'need cacheOptions.cacheTTL');
174
+ logger$6.error(methodName, 'need cacheOptions.cacheTTL');
173
175
  return;
174
176
  }
175
177
 
176
178
  // const
177
179
  const mimeType = mime.lookup(cacheOptions.gsPath);
178
- logger$4.info(methodName, 'cacheOptions', cacheOptions);
179
- logger$4.info(methodName, 'mimeType', mimeType);
180
+ logger$6.info(methodName, 'cacheOptions', cacheOptions);
181
+ logger$6.info(methodName, 'mimeType', mimeType);
180
182
 
181
183
  try {
182
184
  // cache add
@@ -192,7 +194,7 @@ const cacheAdd = async (client, modelName, cacheOptions) => {
192
194
 
193
195
  return cache;
194
196
  } catch (error) {
195
- logger$4.error(methodName, 'error', error);
197
+ logger$6.error(methodName, 'error', error);
196
198
  }
197
199
  };
198
200
 
@@ -206,7 +208,7 @@ const cacheList = async (client) => {
206
208
 
207
209
  // check
208
210
  if (!client) {
209
- logger$4.error(methodName, 'need client');
211
+ logger$6.error(methodName, 'need client');
210
212
  return;
211
213
  }
212
214
 
@@ -220,7 +222,7 @@ const cacheList = async (client) => {
220
222
 
221
223
  return cacheObjs;
222
224
  } catch (error) {
223
- logger$4.error(methodName, 'error', error);
225
+ logger$6.error(methodName, 'error', error);
224
226
  }
225
227
  };
226
228
 
@@ -236,15 +238,15 @@ const cacheUpdate = async (client, cacheName, cacheOptions) => {
236
238
 
237
239
  // check
238
240
  if (!client) {
239
- logger$4.error(methodName, 'need client');
241
+ logger$6.error(methodName, 'need client');
240
242
  return;
241
243
  }
242
244
  if (!cacheName) {
243
- logger$4.error(methodName, 'need cacheName');
245
+ logger$6.error(methodName, 'need cacheName');
244
246
  return;
245
247
  }
246
248
  if (!cacheOptions) {
247
- logger$4.error(methodName, 'need cacheOptions');
249
+ logger$6.error(methodName, 'need cacheOptions');
248
250
  return;
249
251
  }
250
252
 
@@ -257,12 +259,12 @@ const cacheUpdate = async (client, cacheName, cacheOptions) => {
257
259
 
258
260
  return res;
259
261
  } catch (error) {
260
- logger$4.error(methodName, 'error', error);
262
+ logger$6.error(methodName, 'error', error);
261
263
  }
262
264
  };
263
265
 
264
266
  // gemini
265
- const logger$3 = qiao_log_js.Logger('gemini-api.js');
267
+ const logger$5 = qiao_log_js.Logger('gemini-api.js');
266
268
 
267
269
  /**
268
270
  * GeminiAPI
@@ -274,15 +276,15 @@ const GeminiAPI = (options) => {
274
276
 
275
277
  // check
276
278
  if (!options) {
277
- logger$3.error(methodName, 'need options');
279
+ logger$5.error(methodName, 'need options');
278
280
  return;
279
281
  }
280
282
  if (!options.apiKey) {
281
- logger$3.error(methodName, 'need options.apiKey');
283
+ logger$5.error(methodName, 'need options.apiKey');
282
284
  return;
283
285
  }
284
286
  if (!options.modelName) {
285
- logger$3.error(methodName, 'need options.modelName');
287
+ logger$5.error(methodName, 'need options.modelName');
286
288
  return;
287
289
  }
288
290
 
@@ -305,7 +307,7 @@ const GeminiAPI = (options) => {
305
307
  };
306
308
 
307
309
  // gemini
308
- const logger$2 = qiao_log_js.Logger('viho-llm');
310
+ const logger$4 = qiao_log_js.Logger('viho-llm');
309
311
 
310
312
  /**
311
313
  * GeminiVertex
@@ -317,19 +319,19 @@ const GeminiVertex = (options) => {
317
319
 
318
320
  // check
319
321
  if (!options) {
320
- logger$2.error(methodName, 'need options');
322
+ logger$4.error(methodName, 'need options');
321
323
  return;
322
324
  }
323
325
  if (!options.projectId) {
324
- logger$2.error(methodName, 'need options.projectId');
326
+ logger$4.error(methodName, 'need options.projectId');
325
327
  return;
326
328
  }
327
329
  if (!options.location) {
328
- logger$2.error(methodName, 'need options.location');
330
+ logger$4.error(methodName, 'need options.location');
329
331
  return;
330
332
  }
331
333
  if (!options.modelName) {
332
- logger$2.error(methodName, 'need options.modelName');
334
+ logger$4.error(methodName, 'need options.modelName');
333
335
  return;
334
336
  }
335
337
 
@@ -365,7 +367,7 @@ const GeminiVertex = (options) => {
365
367
  };
366
368
 
367
369
  // Logger
368
- const logger$1 = qiao_log_js.Logger('openai-util.js');
370
+ const logger$3 = qiao_log_js.Logger('openai-util.js');
369
371
 
370
372
  /**
371
373
  * chat
@@ -378,11 +380,11 @@ const chat = async (client, chatOptions) => {
378
380
 
379
381
  // check
380
382
  if (!client) {
381
- logger$1.error(methodName, 'need client');
383
+ logger$3.error(methodName, 'need client');
382
384
  return;
383
385
  }
384
386
  if (!chatOptions) {
385
- logger$1.error(methodName, 'need chatOptions');
387
+ logger$3.error(methodName, 'need chatOptions');
386
388
  return;
387
389
  }
388
390
 
@@ -391,7 +393,7 @@ const chat = async (client, chatOptions) => {
391
393
  const completion = await client.chat.completions.create(chatOptions);
392
394
  return completion.choices[0]?.message;
393
395
  } catch (error) {
394
- logger$1.error(methodName, 'error', error);
396
+ logger$3.error(methodName, 'error', error);
395
397
  }
396
398
  };
397
399
 
@@ -407,15 +409,15 @@ const chatWithStreaming = async (client, chatOptions, callbackOptions) => {
407
409
 
408
410
  // check
409
411
  if (!client) {
410
- logger$1.error(methodName, 'need client');
412
+ logger$3.error(methodName, 'need client');
411
413
  return;
412
414
  }
413
415
  if (!chatOptions) {
414
- logger$1.error(methodName, 'need chatOptions');
416
+ logger$3.error(methodName, 'need chatOptions');
415
417
  return;
416
418
  }
417
419
  if (!callbackOptions) {
418
- logger$1.error(methodName, 'need callbackOptions');
420
+ logger$3.error(methodName, 'need callbackOptions');
419
421
  return;
420
422
  }
421
423
 
@@ -469,7 +471,7 @@ const chatWithStreaming = async (client, chatOptions, callbackOptions) => {
469
471
  };
470
472
 
471
473
  // openai
472
- const logger = qiao_log_js.Logger('openai.js');
474
+ const logger$2 = qiao_log_js.Logger('openai.js');
473
475
 
474
476
  /**
475
477
  * OpenAI
@@ -481,24 +483,28 @@ const OpenAIAPI = (options) => {
481
483
 
482
484
  // check
483
485
  if (!options) {
484
- logger.error(methodName, 'need options');
486
+ logger$2.error(methodName, 'need options');
485
487
  return;
486
488
  }
487
489
  if (!options.apiKey) {
488
- logger.error(methodName, 'need options.apiKey');
490
+ logger$2.error(methodName, 'need options.apiKey');
489
491
  return;
490
492
  }
491
493
  if (!options.baseURL) {
492
- logger.error(methodName, 'need options.baseURL');
494
+ logger$2.error(methodName, 'need options.baseURL');
493
495
  return;
494
496
  }
495
497
 
496
498
  // openai
497
499
  const openai = {};
498
- openai.client = new OpenAI({
500
+ const clientOptions = {
499
501
  apiKey: options.apiKey,
500
502
  baseURL: options.baseURL,
501
- });
503
+ };
504
+ if (options.defaultHeaders) {
505
+ clientOptions.defaultHeaders = options.defaultHeaders;
506
+ }
507
+ openai.client = new OpenAI(clientOptions);
502
508
 
503
509
  // chat
504
510
  openai.chat = async (chatOptions) => {
@@ -514,6 +520,281 @@ const OpenAIAPI = (options) => {
514
520
  return openai;
515
521
  };
516
522
 
523
+ // crypto
524
+ const logger$1 = qiao_log_js.Logger('liblib-util.js');
525
+
526
+ /**
527
+ * generateSignature
528
+ * @param {*} uri
529
+ * @param {*} secretKey
530
+ * @returns
531
+ */
532
+ const generateSignature = (uri, secretKey) => {
533
+ const timestamp = String(Date.now());
534
+ const signatureNonce = crypto.randomBytes(8).toString('hex');
535
+ const content = `${uri}&${timestamp}&${signatureNonce}`;
536
+
537
+ const hmac = crypto.createHmac('sha1', secretKey);
538
+ hmac.update(content);
539
+ const signature = hmac.digest('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
540
+
541
+ return { signature, timestamp, signatureNonce };
542
+ };
543
+
544
+ /**
545
+ * request
546
+ * @param {*} baseURL
547
+ * @param {*} accessKey
548
+ * @param {*} secretKey
549
+ * @param {*} uri
550
+ * @param {*} body
551
+ * @returns
552
+ */
553
+ const request = (baseURL, accessKey, secretKey, uri, body) => {
554
+ const methodName = 'request';
555
+
556
+ return new Promise((resolve, reject) => {
557
+ const { signature, timestamp, signatureNonce } = generateSignature(uri, secretKey);
558
+ const query =
559
+ `AccessKey=${accessKey}` +
560
+ `&Signature=${signature}` +
561
+ `&Timestamp=${timestamp}` +
562
+ `&SignatureNonce=${signatureNonce}`;
563
+
564
+ const postData = JSON.stringify(body);
565
+
566
+ const options = {
567
+ hostname: baseURL,
568
+ path: `${uri}?${query}`,
569
+ method: 'POST',
570
+ headers: {
571
+ 'Content-Type': 'application/json',
572
+ 'Content-Length': Buffer.byteLength(postData),
573
+ },
574
+ };
575
+
576
+ const req = https.request(options, (res) => {
577
+ let data = '';
578
+ res.on('data', (chunk) => {
579
+ data += chunk;
580
+ });
581
+ res.on('end', () => {
582
+ try {
583
+ resolve(JSON.parse(data));
584
+ } catch (e) {
585
+ logger$1.error(methodName, 'JSON parse error', data);
586
+ reject(new Error('JSON parse error: ' + data));
587
+ }
588
+ });
589
+ });
590
+
591
+ req.on('error', (error) => {
592
+ logger$1.error(methodName, 'request error', error);
593
+ reject(error);
594
+ });
595
+ req.write(postData);
596
+ req.end();
597
+ });
598
+ };
599
+
600
+ /**
601
+ * text2img
602
+ * @param {*} baseURL
603
+ * @param {*} accessKey
604
+ * @param {*} secretKey
605
+ * @param {*} prompt
606
+ * @param {*} options
607
+ * @returns
608
+ */
609
+ const text2img = (baseURL, accessKey, secretKey, prompt, options) => {
610
+ const methodName = 'text2img';
611
+
612
+ // check
613
+ if (!prompt) {
614
+ logger$1.error(methodName, 'need prompt');
615
+ return;
616
+ }
617
+
618
+ options = options || {};
619
+ const generateParams = {
620
+ prompt: prompt,
621
+ aspectRatio: options.aspectRatio || 'portrait',
622
+ imgCount: options.imgCount || 1,
623
+ steps: options.steps || 30,
624
+ };
625
+
626
+ if (options.width && options.height) {
627
+ delete generateParams.aspectRatio;
628
+ generateParams.imageSize = {
629
+ width: options.width,
630
+ height: options.height,
631
+ };
632
+ }
633
+
634
+ if (options.controlnet) {
635
+ generateParams.controlnet = options.controlnet;
636
+ }
637
+
638
+ return request(baseURL, accessKey, secretKey, '/api/generate/webui/text2img/ultra', {
639
+ templateUuid: '5d7e67009b344550bc1aa6ccbfa1d7f4',
640
+ generateParams: generateParams,
641
+ });
642
+ };
643
+
644
+ /**
645
+ * img2img
646
+ * @param {*} baseURL
647
+ * @param {*} accessKey
648
+ * @param {*} secretKey
649
+ * @param {*} prompt
650
+ * @param {*} sourceImage
651
+ * @param {*} options
652
+ * @returns
653
+ */
654
+ const img2img = (baseURL, accessKey, secretKey, prompt, sourceImage, options) => {
655
+ const methodName = 'img2img';
656
+
657
+ // check
658
+ if (!prompt) {
659
+ logger$1.error(methodName, 'need prompt');
660
+ return;
661
+ }
662
+ if (!sourceImage) {
663
+ logger$1.error(methodName, 'need sourceImage');
664
+ return;
665
+ }
666
+
667
+ options = options || {};
668
+ const generateParams = {
669
+ prompt: prompt,
670
+ sourceImage: sourceImage,
671
+ imgCount: options.imgCount || 1,
672
+ };
673
+
674
+ if (options.controlnet) {
675
+ generateParams.controlnet = options.controlnet;
676
+ }
677
+
678
+ return request(baseURL, accessKey, secretKey, '/api/generate/webui/img2img/ultra', {
679
+ templateUuid: '07e00af4fc464c7ab55ff906f8acf1b7',
680
+ generateParams: generateParams,
681
+ });
682
+ };
683
+
684
+ /**
685
+ * queryStatus
686
+ * @param {*} baseURL
687
+ * @param {*} accessKey
688
+ * @param {*} secretKey
689
+ * @param {*} generateUuid
690
+ * @returns
691
+ */
692
+ const queryStatus = (baseURL, accessKey, secretKey, generateUuid) => {
693
+ return request(baseURL, accessKey, secretKey, '/api/generate/webui/status', {
694
+ generateUuid: generateUuid,
695
+ });
696
+ };
697
+
698
+ /**
699
+ * waitForResult
700
+ * @param {*} baseURL
701
+ * @param {*} accessKey
702
+ * @param {*} secretKey
703
+ * @param {*} generateUuid
704
+ * @param {*} intervalMs
705
+ * @param {*} maxRetries
706
+ * @returns
707
+ */
708
+ const waitForResult = (baseURL, accessKey, secretKey, generateUuid, intervalMs, maxRetries) => {
709
+ intervalMs = intervalMs || 3000;
710
+ maxRetries = maxRetries || 60;
711
+
712
+ return new Promise((resolve, reject) => {
713
+ let attempt = 0;
714
+
715
+ function poll() {
716
+ attempt++;
717
+ queryStatus(baseURL, accessKey, secretKey, generateUuid)
718
+ .then((res) => {
719
+ const status = res.data && res.data.generateStatus;
720
+
721
+ if (status === 5) {
722
+ return resolve(res.data);
723
+ }
724
+ if (status === 6 || status === 7) {
725
+ return reject(new Error('Generation failed: ' + (res.data.generateMsg || 'unknown')));
726
+ }
727
+
728
+ if (attempt >= maxRetries) {
729
+ return reject(new Error('Polling timeout after ' + maxRetries + ' retries'));
730
+ }
731
+
732
+ setTimeout(poll, intervalMs);
733
+ })
734
+ .catch(reject);
735
+ }
736
+
737
+ poll();
738
+ });
739
+ };
740
+
741
+ // util
742
+ const logger = qiao_log_js.Logger('liblib.js');
743
+
744
+ /**
745
+ * LibLibAPI
746
+ * @param {*} options
747
+ * @returns
748
+ */
749
+ const LibLibAPI = (options) => {
750
+ const methodName = 'LibLibAPI';
751
+
752
+ // check
753
+ if (!options) {
754
+ logger.error(methodName, 'need options');
755
+ return;
756
+ }
757
+ if (!options.accessKey) {
758
+ logger.error(methodName, 'need options.accessKey');
759
+ return;
760
+ }
761
+ if (!options.secretKey) {
762
+ logger.error(methodName, 'need options.secretKey');
763
+ return;
764
+ }
765
+
766
+ // config
767
+ const baseURL = options.baseURL || 'openapi.liblibai.cloud';
768
+ const accessKey = options.accessKey;
769
+ const secretKey = options.secretKey;
770
+
771
+ // liblib
772
+ const liblib = {};
773
+
774
+ // text2img
775
+ liblib.text2img = async (prompt, imgOptions) => {
776
+ return await text2img(baseURL, accessKey, secretKey, prompt, imgOptions);
777
+ };
778
+
779
+ // img2img
780
+ liblib.img2img = async (prompt, sourceImage, imgOptions) => {
781
+ return await img2img(baseURL, accessKey, secretKey, prompt, sourceImage, imgOptions);
782
+ };
783
+
784
+ // queryStatus
785
+ liblib.queryStatus = async (generateUuid) => {
786
+ return await queryStatus(baseURL, accessKey, secretKey, generateUuid);
787
+ };
788
+
789
+ // waitForResult
790
+ liblib.waitForResult = async (generateUuid, intervalMs, maxRetries) => {
791
+ return await waitForResult(baseURL, accessKey, secretKey, generateUuid, intervalMs, maxRetries);
792
+ };
793
+
794
+ //
795
+ return liblib;
796
+ };
797
+
517
798
  /**
518
799
  * callLLM
519
800
  * @param {*} options
@@ -608,5 +889,6 @@ const runAgents = async (agents) => {
608
889
 
609
890
  exports.GeminiAPI = GeminiAPI;
610
891
  exports.GeminiVertex = GeminiVertex;
892
+ exports.LibLibAPI = LibLibAPI;
611
893
  exports.OpenAIAPI = OpenAIAPI;
612
894
  exports.runAgents = runAgents;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "viho-llm",
3
- "version": "1.0.9",
3
+ "version": "1.1.1",
4
4
  "description": "Utility library for working with multiple LLM providers (Google Gemini and OpenAI), providing common tools and helpers for AI interactions",
5
5
  "keywords": [
6
6
  "llm",
@@ -68,5 +68,5 @@
68
68
  }
69
69
  }
70
70
  },
71
- "gitHead": "24672073850eae9daef6781b1eec972b899381ad"
71
+ "gitHead": "990e74da184751aaee5085fe87a4a9f87fa33064"
72
72
  }
package/src/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from './models/gemini-api.js';
2
2
  export * from './models/gemini-vertex.js';
3
3
  export * from './models/openai.js';
4
+ export * from './models/liblib.js';
4
5
  export * from './agents/agent.js';
@@ -0,0 +1,224 @@
1
+ // crypto
2
+ import crypto from 'crypto';
3
+
4
+ // https
5
+ import https from 'https';
6
+
7
+ // Logger
8
+ import { Logger } from 'qiao.log.js';
9
+ const logger = Logger('liblib-util.js');
10
+
11
+ /**
12
+ * generateSignature
13
+ * @param {*} uri
14
+ * @param {*} secretKey
15
+ * @returns
16
+ */
17
+ export const generateSignature = (uri, secretKey) => {
18
+ const timestamp = String(Date.now());
19
+ const signatureNonce = crypto.randomBytes(8).toString('hex');
20
+ const content = `${uri}&${timestamp}&${signatureNonce}`;
21
+
22
+ const hmac = crypto.createHmac('sha1', secretKey);
23
+ hmac.update(content);
24
+ const signature = hmac.digest('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
25
+
26
+ return { signature, timestamp, signatureNonce };
27
+ };
28
+
29
+ /**
30
+ * request
31
+ * @param {*} baseURL
32
+ * @param {*} accessKey
33
+ * @param {*} secretKey
34
+ * @param {*} uri
35
+ * @param {*} body
36
+ * @returns
37
+ */
38
+ export const request = (baseURL, accessKey, secretKey, uri, body) => {
39
+ const methodName = 'request';
40
+
41
+ return new Promise((resolve, reject) => {
42
+ const { signature, timestamp, signatureNonce } = generateSignature(uri, secretKey);
43
+ const query =
44
+ `AccessKey=${accessKey}` +
45
+ `&Signature=${signature}` +
46
+ `&Timestamp=${timestamp}` +
47
+ `&SignatureNonce=${signatureNonce}`;
48
+
49
+ const postData = JSON.stringify(body);
50
+
51
+ const options = {
52
+ hostname: baseURL,
53
+ path: `${uri}?${query}`,
54
+ method: 'POST',
55
+ headers: {
56
+ 'Content-Type': 'application/json',
57
+ 'Content-Length': Buffer.byteLength(postData),
58
+ },
59
+ };
60
+
61
+ const req = https.request(options, (res) => {
62
+ let data = '';
63
+ res.on('data', (chunk) => {
64
+ data += chunk;
65
+ });
66
+ res.on('end', () => {
67
+ try {
68
+ resolve(JSON.parse(data));
69
+ } catch (e) {
70
+ logger.error(methodName, 'JSON parse error', data);
71
+ reject(new Error('JSON parse error: ' + data));
72
+ }
73
+ });
74
+ });
75
+
76
+ req.on('error', (error) => {
77
+ logger.error(methodName, 'request error', error);
78
+ reject(error);
79
+ });
80
+ req.write(postData);
81
+ req.end();
82
+ });
83
+ };
84
+
85
+ /**
86
+ * text2img
87
+ * @param {*} baseURL
88
+ * @param {*} accessKey
89
+ * @param {*} secretKey
90
+ * @param {*} prompt
91
+ * @param {*} options
92
+ * @returns
93
+ */
94
+ export const text2img = (baseURL, accessKey, secretKey, prompt, options) => {
95
+ const methodName = 'text2img';
96
+
97
+ // check
98
+ if (!prompt) {
99
+ logger.error(methodName, 'need prompt');
100
+ return;
101
+ }
102
+
103
+ options = options || {};
104
+ const generateParams = {
105
+ prompt: prompt,
106
+ aspectRatio: options.aspectRatio || 'portrait',
107
+ imgCount: options.imgCount || 1,
108
+ steps: options.steps || 30,
109
+ };
110
+
111
+ if (options.width && options.height) {
112
+ delete generateParams.aspectRatio;
113
+ generateParams.imageSize = {
114
+ width: options.width,
115
+ height: options.height,
116
+ };
117
+ }
118
+
119
+ if (options.controlnet) {
120
+ generateParams.controlnet = options.controlnet;
121
+ }
122
+
123
+ return request(baseURL, accessKey, secretKey, '/api/generate/webui/text2img/ultra', {
124
+ templateUuid: '5d7e67009b344550bc1aa6ccbfa1d7f4',
125
+ generateParams: generateParams,
126
+ });
127
+ };
128
+
129
+ /**
130
+ * img2img
131
+ * @param {*} baseURL
132
+ * @param {*} accessKey
133
+ * @param {*} secretKey
134
+ * @param {*} prompt
135
+ * @param {*} sourceImage
136
+ * @param {*} options
137
+ * @returns
138
+ */
139
+ export const img2img = (baseURL, accessKey, secretKey, prompt, sourceImage, options) => {
140
+ const methodName = 'img2img';
141
+
142
+ // check
143
+ if (!prompt) {
144
+ logger.error(methodName, 'need prompt');
145
+ return;
146
+ }
147
+ if (!sourceImage) {
148
+ logger.error(methodName, 'need sourceImage');
149
+ return;
150
+ }
151
+
152
+ options = options || {};
153
+ const generateParams = {
154
+ prompt: prompt,
155
+ sourceImage: sourceImage,
156
+ imgCount: options.imgCount || 1,
157
+ };
158
+
159
+ if (options.controlnet) {
160
+ generateParams.controlnet = options.controlnet;
161
+ }
162
+
163
+ return request(baseURL, accessKey, secretKey, '/api/generate/webui/img2img/ultra', {
164
+ templateUuid: '07e00af4fc464c7ab55ff906f8acf1b7',
165
+ generateParams: generateParams,
166
+ });
167
+ };
168
+
169
+ /**
170
+ * queryStatus
171
+ * @param {*} baseURL
172
+ * @param {*} accessKey
173
+ * @param {*} secretKey
174
+ * @param {*} generateUuid
175
+ * @returns
176
+ */
177
+ export const queryStatus = (baseURL, accessKey, secretKey, generateUuid) => {
178
+ return request(baseURL, accessKey, secretKey, '/api/generate/webui/status', {
179
+ generateUuid: generateUuid,
180
+ });
181
+ };
182
+
183
+ /**
184
+ * waitForResult
185
+ * @param {*} baseURL
186
+ * @param {*} accessKey
187
+ * @param {*} secretKey
188
+ * @param {*} generateUuid
189
+ * @param {*} intervalMs
190
+ * @param {*} maxRetries
191
+ * @returns
192
+ */
193
+ export const waitForResult = (baseURL, accessKey, secretKey, generateUuid, intervalMs, maxRetries) => {
194
+ intervalMs = intervalMs || 3000;
195
+ maxRetries = maxRetries || 60;
196
+
197
+ return new Promise((resolve, reject) => {
198
+ let attempt = 0;
199
+
200
+ function poll() {
201
+ attempt++;
202
+ queryStatus(baseURL, accessKey, secretKey, generateUuid)
203
+ .then((res) => {
204
+ const status = res.data && res.data.generateStatus;
205
+
206
+ if (status === 5) {
207
+ return resolve(res.data);
208
+ }
209
+ if (status === 6 || status === 7) {
210
+ return reject(new Error('Generation failed: ' + (res.data.generateMsg || 'unknown')));
211
+ }
212
+
213
+ if (attempt >= maxRetries) {
214
+ return reject(new Error('Polling timeout after ' + maxRetries + ' retries'));
215
+ }
216
+
217
+ setTimeout(poll, intervalMs);
218
+ })
219
+ .catch(reject);
220
+ }
221
+
222
+ poll();
223
+ });
224
+ };
@@ -0,0 +1,60 @@
1
+ // util
2
+ import { text2img, img2img, queryStatus, waitForResult } from './liblib-util.js';
3
+
4
+ // Logger
5
+ import { Logger } from 'qiao.log.js';
6
+ const logger = Logger('liblib.js');
7
+
8
+ /**
9
+ * LibLibAPI
10
+ * @param {*} options
11
+ * @returns
12
+ */
13
+ export const LibLibAPI = (options) => {
14
+ const methodName = 'LibLibAPI';
15
+
16
+ // check
17
+ if (!options) {
18
+ logger.error(methodName, 'need options');
19
+ return;
20
+ }
21
+ if (!options.accessKey) {
22
+ logger.error(methodName, 'need options.accessKey');
23
+ return;
24
+ }
25
+ if (!options.secretKey) {
26
+ logger.error(methodName, 'need options.secretKey');
27
+ return;
28
+ }
29
+
30
+ // config
31
+ const baseURL = options.baseURL || 'openapi.liblibai.cloud';
32
+ const accessKey = options.accessKey;
33
+ const secretKey = options.secretKey;
34
+
35
+ // liblib
36
+ const liblib = {};
37
+
38
+ // text2img
39
+ liblib.text2img = async (prompt, imgOptions) => {
40
+ return await text2img(baseURL, accessKey, secretKey, prompt, imgOptions);
41
+ };
42
+
43
+ // img2img
44
+ liblib.img2img = async (prompt, sourceImage, imgOptions) => {
45
+ return await img2img(baseURL, accessKey, secretKey, prompt, sourceImage, imgOptions);
46
+ };
47
+
48
+ // queryStatus
49
+ liblib.queryStatus = async (generateUuid) => {
50
+ return await queryStatus(baseURL, accessKey, secretKey, generateUuid);
51
+ };
52
+
53
+ // waitForResult
54
+ liblib.waitForResult = async (generateUuid, intervalMs, maxRetries) => {
55
+ return await waitForResult(baseURL, accessKey, secretKey, generateUuid, intervalMs, maxRetries);
56
+ };
57
+
58
+ //
59
+ return liblib;
60
+ };
@@ -32,10 +32,14 @@ export const OpenAIAPI = (options) => {
32
32
 
33
33
  // openai
34
34
  const openai = {};
35
- openai.client = new OpenAI({
35
+ const clientOptions = {
36
36
  apiKey: options.apiKey,
37
37
  baseURL: options.baseURL,
38
- });
38
+ };
39
+ if (options.defaultHeaders) {
40
+ clientOptions.defaultHeaders = options.defaultHeaders;
41
+ }
42
+ openai.client = new OpenAI(clientOptions);
39
43
 
40
44
  // chat
41
45
  openai.chat = async (chatOptions) => {