utilitas 1999.1.57 → 1999.1.59

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/gen.mjs CHANGED
@@ -1,9 +1,12 @@
1
+ import {
2
+ ensureString, log as _log, need, throwError, tryUntil,
3
+ } from './utilitas.mjs';
4
+
1
5
  import { convert, MIME_PNG } from './storage.mjs';
2
- import { ensureString, need, throwError, tryUntil } from './utilitas.mjs';
3
6
  import { assertCommand, exec } from './shell.mjs';
4
7
 
5
8
  const _NEED = ['OpenAI'];
6
-
9
+ const log = (cnt, opt) => _log(cnt, import.meta.url, { time: 1, ...opt || {} });
7
10
  const [
8
11
  clients, OPENAI, GEMINI, BASE64, BUFFER, ERROR_GENERATING, IMAGEN_MODEL,
9
12
  OPENAI_MODEL, VEO_MODEL,
@@ -45,7 +48,7 @@ const extractVideo = async (data, options) => await convert(
45
48
  data, { input: BASE64, suffix: 'mp4', ...options || {} }
46
49
  );
47
50
 
48
- const generateImage = async (prompt, options) => {
51
+ const image = async (prompt, options) => {
49
52
  let provider = ensureString(options?.provider, { case: 'UP' });
50
53
  if (!provider && clients?.[GEMINI]?.apiKey) { provider = GEMINI; }
51
54
  if (!provider && clients?.[OPENAI]) { provider = OPENAI; }
@@ -79,15 +82,58 @@ const generateImage = async (prompt, options) => {
79
82
  }
80
83
  return resp?.data;
81
84
  case GEMINI:
85
+ // Image editing failed with the following error: imagen-3.0-capability-001 is unavailable.
86
+ // @todo: https://cloud.google.com/vertex-ai/generative-ai/docs/image/overview#feature-launch-stage
87
+ // cat << EOF > request.json
88
+ // {
89
+ // "endpoint": "projects/backend-alpha-97077/locations/us-central1/publishers/google/models/imagen-3.0-capability-001",
90
+ // "instances": [
91
+ // {
92
+ // "prompt": "ENTER PROMPT HERE",
93
+ // "referenceImages": [
94
+ // {
95
+ // "referenceId": 1,
96
+ // "referenceType": "REFERENCE_TYPE_SUBJECT",
97
+ // "referenceImage": {
98
+ // "bytesBase64Encoded":
99
+ // },
100
+ // "subjectImageConfig" {
101
+ // "subjectDescription": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
102
+ // "subjectType": "SUBJECT_TYPE_DEFAULT"
103
+ // }
104
+ // }
105
+ // ],
106
+ // }
107
+ // ],
108
+ // "parameters": {
109
+ // "aspectRatio": "1:1",
110
+ // "sampleCount": 4,
111
+ // "negativePrompt": "",
112
+ // "enhancePrompt": false,
113
+ // "personGeneration": "",
114
+ // "safetySetting": "",
115
+ // "addWatermark": true,
116
+ // "includeRaiReason": true,
117
+ // "language": "auto",
118
+ // }
119
+ // }
120
+ // curl \
121
+ // -X POST \
122
+ // -H "Content-Type: application/json" \
123
+ // -H "Authorization: Bearer $(gcloud auth print-access-token)" \
124
+ // "https://${API_ENDPOINT}/v1/projects/${PROJECT_ID}/locations/${LOCATION_ID}/publishers/google/models/${MODEL_ID}:predict" -d '@request.json'
125
+ // ARGs: https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/imagen-api?authuser=4#rest_1
82
126
  var resp = await (await fetch(
83
127
  'https://generativelanguage.googleapis.com/v1beta/models/'
84
128
  + `${IMAGEN_MODEL}:predict?key=${client.apiKey}`, {
85
129
  method: 'POST', headers: { 'Content-Type': 'application/json' },
86
130
  body: JSON.stringify({
87
131
  instances: [{ prompt }], parameters: {
88
- sampleCount: n, aspectRatio: '16:9',
132
+ // "1:1" (default), "3:4", "4:3", "9:16", and "16:9"
133
+ aspectRatio: '16:9', includeRaiReason: true,
134
+ personGeneration: 'allow_adult', sampleCount: n,
89
135
  ...options?.params || {},
90
- }, // "1:1" (default), "3:4", "4:3", "9:16", and "16:9"
136
+ },
91
137
  })
92
138
  })).json();
93
139
  assert(!resp?.error, resp?.error?.message || ERROR_GENERATING);
@@ -119,7 +165,7 @@ const getGeminiAccessToken = async (credentials) => {
119
165
  return tokResp;
120
166
  };
121
167
 
122
- const getGeminiVideo = async (jobId) => {
168
+ const getGeminiVideo = async (jobId, accessToken) => {
123
169
  const client = clients?.[GEMINI];
124
170
  assert(client, 'No available video generation provider.');
125
171
  const resp = await (await fetch(
@@ -128,20 +174,16 @@ const getGeminiVideo = async (jobId) => {
128
174
  + `${VEO_MODEL}:fetchPredictOperation`, {
129
175
  method: 'POST', headers: {
130
176
  'Content-Type': 'application/json',
131
- 'Authorization': `Bearer ${client.accessToken}`,
132
- },
133
- body: JSON.stringify({
134
- operationName: jobId,
135
- })
177
+ 'Authorization': `Bearer ${accessToken}`,
178
+ }, body: JSON.stringify({ operationName: jobId })
136
179
  })).json();
137
- assert(
138
- resp?.response?.videos?.length,
139
- `Waiting for Gemini video generation: \`${jobId}\`...`
140
- );
180
+ assert(resp?.response?.videos?.length,
181
+ 'Waiting for Gemini video generation: '
182
+ + jobId.replace(/^.*\/([^/]+)$/, '$1'));
141
183
  return resp?.response?.videos;
142
184
  };
143
185
 
144
- const generateVideo = async (prompt, options) => {
186
+ const video = async (prompt, options) => {
145
187
  let provider = ensureString(options?.provider, { case: 'UP' });
146
188
  if (!provider
147
189
  && clients?.[GEMINI]?.credentials
@@ -181,10 +223,9 @@ const generateVideo = async (prompt, options) => {
181
223
  resp?.error?.message || ERROR_GENERATING
182
224
  );
183
225
  if (options?.generateRaw) { return resp; }
184
- var videos = await tryUntil(
185
- async () => await getGeminiVideo(resp.name),
186
- { maxTry: 60 * 10, log: true }
187
- );
226
+ var videos = await tryUntil(async () => await getGeminiVideo(
227
+ resp.name, accessToken
228
+ ), { maxTry: 60 * 10, log });
188
229
  assert(videos?.length, 'Failed to generate Gemini video.');
189
230
  if (options?.videoRaw) { return videos; }
190
231
  return await Promise.all(videos.map(async x => ({
@@ -200,8 +241,7 @@ const generateVideo = async (prompt, options) => {
200
241
  export default init;
201
242
  export {
202
243
  _NEED,
203
- generateImage,
204
- generateVideo,
205
- getGeminiVideo,
244
+ image,
206
245
  init,
246
+ video,
207
247
  };
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": "1999.1.57",
4
+ "version": "1999.1.59",
5
5
  "private": false,
6
6
  "homepage": "https://github.com/Leask/utilitas",
7
7
  "main": "index.mjs",
package/lib/utilitas.mjs CHANGED
@@ -394,6 +394,7 @@ const log = (content, filename, options) => {
394
394
  const args = ['[' + color.red(name) + color.yellow(strTime) + ']'
395
395
  + (isErr ? '' : ` ${content}`)];
396
396
  if (isErr) { args.push(content); }
397
+ if (options?.return) { return args[0]; }
397
398
  return console.info.apply(null, args);
398
399
  };
399
400
 
@@ -669,12 +670,15 @@ const tryUntil = async (fnTry, options) => {
669
670
  interval: 1000 * 1, maxTry: Infinity, log: false, error: 'Operation failed.',
670
671
  verify: async (err, res) => { return !err; }, ...options || {}
671
672
  };
672
- let [curTry, result, err] = [0, null, null];
673
+ let [curTry, result, err, msg] = [0, null, null, null];
673
674
  do {
674
675
  try {
675
676
  assert(await options.verify((err = null), (result = await fnTry())), options.error);
676
677
  } catch (e) {
677
- (err = e) && options?.log && console.log(err?.message || err);
678
+ (err = e) && (msg = err?.message || err) && (
679
+ Function.isFunction(options?.log)
680
+ ? await options.log(msg) : console.log(msg)
681
+ );
678
682
  await timeout(options.interval);
679
683
  }
680
684
  } while (++curTry < options.maxTry && err)
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": "1999.1.57",
4
+ "version": "1999.1.59",
5
5
  "private": false,
6
6
  "homepage": "https://github.com/Leask/utilitas",
7
7
  "main": "index.mjs",