@aj-archipelago/cortex 1.3.8 → 1.3.9

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.
@@ -191,7 +191,7 @@ async function deleteBlob(requestId) {
191
191
  return result;
192
192
  }
193
193
 
194
- async function uploadBlob(context, req, saveToLocal = false, useGoogle = false, filePath=null) {
194
+ async function uploadBlob(context, req, saveToLocal = false, useGoogle = false, filePath=null, hash=null) {
195
195
  return new Promise((resolve, reject) => {
196
196
  try {
197
197
  let requestId = uuidv4();
@@ -201,7 +201,7 @@ async function uploadBlob(context, req, saveToLocal = false, useGoogle = false,
201
201
  if (filePath) {
202
202
  const file = fs.createReadStream(filePath);
203
203
  const filename = path.basename(filePath);
204
- uploadFile(context, requestId, body, saveToLocal, useGoogle, file, filename, resolve)
204
+ uploadFile(context, requestId, body, saveToLocal, useGoogle, file, filename, resolve, hash);
205
205
  } else {
206
206
  // Otherwise, continue working with form-data
207
207
  const busboy = Busboy({ headers: req.headers });
@@ -215,7 +215,7 @@ async function uploadBlob(context, req, saveToLocal = false, useGoogle = false,
215
215
  });
216
216
 
217
217
  busboy.on("file", async (fieldname, file, filename) => {
218
- uploadFile(context, requestId, body, saveToLocal, useGoogle, file, filename?.filename || filename, resolve)
218
+ uploadFile(context, requestId, body, saveToLocal, useGoogle, file, filename?.filename || filename, resolve, hash);
219
219
  });
220
220
 
221
221
  busboy.on("error", (error) => {
@@ -240,7 +240,7 @@ async function uploadBlob(context, req, saveToLocal = false, useGoogle = false,
240
240
  });
241
241
  }
242
242
 
243
- async function uploadFile(context, requestId, body, saveToLocal, useGoogle, file, filename, resolve) {
243
+ async function uploadFile(context, requestId, body, saveToLocal, useGoogle, file, filename, resolve, hash=null) {
244
244
  // do not use Google if the file is not an image or video
245
245
  const ext = path.extname(filename).toLowerCase();
246
246
  const canUseGoogle = IMAGE_EXTENSIONS.includes(ext) || VIDEO_EXTENSIONS.includes(ext) || AUDIO_EXTENSIONS.includes(ext);
@@ -306,16 +306,29 @@ async function uploadFile(context, requestId, body, saveToLocal, useGoogle, file
306
306
  const { url } = body;
307
307
  const gcsFile = gcs.bucket(GCS_BUCKETNAME).file(encodedFilename);
308
308
  const writeStream = gcsFile.createWriteStream();
309
-
309
+
310
310
  const response = await axios({
311
311
  method: "get",
312
312
  url: url,
313
313
  responseType: "stream",
314
314
  });
315
-
316
- // pipe the Axios response stream directly into the GCS Write Stream
315
+
316
+ // // Get the total file size from the response headers
317
+ // const totalSize = Number(response.headers["content-length"]);
318
+ // let downloadedSize = 0;
319
+
320
+ // // Listen to the 'data' event to track the progress
321
+ // response.data.on("data", (chunk) => {
322
+ // downloadedSize += chunk.length;
323
+
324
+ // // Calculate and display the progress
325
+ // const progress = (downloadedSize / totalSize) * 100;
326
+ // console.log(`Progress gsc of ${encodedFilename}: ${progress.toFixed(2)}%`);
327
+ // });
328
+
329
+ // Pipe the Axios response stream directly into the GCS Write Stream
317
330
  response.data.pipe(writeStream);
318
-
331
+
319
332
  await new Promise((resolve, reject) => {
320
333
  writeStream.on("finish", resolve);
321
334
  writeStream.on("error", reject);
@@ -324,6 +337,12 @@ async function uploadFile(context, requestId, body, saveToLocal, useGoogle, file
324
337
  body.gcs = `gs://${GCS_BUCKETNAME}/${encodedFilename}`;
325
338
  }
326
339
 
340
+ if(!body.filename) {
341
+ body.filename = filename;
342
+ }
343
+ if(hash && !body.hash) {
344
+ body.hash = hash;
345
+ }
327
346
  resolve(body); // Resolve the promise
328
347
  }
329
348
 
@@ -120,7 +120,7 @@ async function main(context, req) {
120
120
  return;
121
121
  }
122
122
 
123
- const { uri, requestId, save, hash, checkHash, fetch, load, restore } = req.body?.params || req.query;
123
+ const { uri, requestId, save, hash, checkHash, clearHash, fetch, load, restore } = req.body?.params || req.query;
124
124
 
125
125
  const filepond = fetch || restore || load;
126
126
  if (req.method.toLowerCase() === `get` && filepond) {
@@ -163,6 +163,24 @@ async function main(context, req) {
163
163
  return;
164
164
  }
165
165
 
166
+ if(hash && clearHash){
167
+ try {
168
+ const hashValue = await getFileStoreMap(hash);
169
+ await removeFromFileStoreMap(hash);
170
+ context.res = {
171
+ status: 200,
172
+ body: hashValue ? `Hash ${hash} removed` : `Hash ${hash} not found`
173
+ };
174
+ } catch (error) {
175
+ context.res = {
176
+ status: 500,
177
+ body: `Error occurred during hash cleanup: ${error}`
178
+ };
179
+ console.log('Error occurred during hash cleanup:', error);
180
+ }
181
+ return
182
+ }
183
+
166
184
  if(hash && checkHash){ //check if hash exists
167
185
  context.log(`Checking hash: ${hash}`);
168
186
  const result = await getFileStoreMap(hash);
@@ -188,7 +206,7 @@ async function main(context, req) {
188
206
 
189
207
  if (req.method.toLowerCase() === `post`) {
190
208
  const { useGoogle } = req.body?.params || req.query;
191
- const { url } = await uploadBlob(context, req, !useAzure, useGoogle);
209
+ const { url } = await uploadBlob(context, req, !useAzure, useGoogle, null, hash);
192
210
  context.log(`File url: ${url}`);
193
211
  if(hash && context?.res?.body){ //save hash after upload
194
212
  await setFileStoreMap(hash, context.res.body);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aj-archipelago/cortex",
3
- "version": "1.3.8",
3
+ "version": "1.3.9",
4
4
  "description": "Cortex is a GraphQL API for AI. It provides a simple, extensible interface for using AI services from OpenAI, Azure and others.",
5
5
  "private": false,
6
6
  "repository": {
@@ -81,17 +81,6 @@ class AzureVideoTranslatePlugin extends ModelPlugin {
81
81
  throw new Error(this.jsonBuffer);
82
82
  }
83
83
 
84
- if (isValidJSON(this.jsonBuffer)) {
85
- const parsedData = JSON.parse(this.jsonBuffer);
86
- if (parsedData.progress !== undefined) {
87
- publishRequestProgress({
88
- requestId: this.requestId,
89
- progress: parsedData.progress,
90
- info: this.jsonBuffer
91
- });
92
- }
93
- }
94
-
95
84
  onData(this.jsonBuffer);
96
85
  this.jsonBuffer = '';
97
86
  this.jsonDepth = 0;
@@ -118,11 +107,34 @@ class AzureVideoTranslatePlugin extends ModelPlugin {
118
107
  let finalJson = '';
119
108
  this.handleStream(response.data,
120
109
  (data) => {
121
- publishRequestProgress({
122
- requestId: this.requestId,
123
- info: data
124
- });
110
+ let sent = false;
111
+ if (isValidJSON(data)) {
112
+ const parsedData = JSON.parse(data);
113
+ if (parsedData.progress !== undefined) {
114
+ let timeInfo = '';
115
+ if (parsedData.estimated_time_remaining && parsedData.elapsed_time) {
116
+ const minutes = Math.ceil(parsedData.estimated_time_remaining / 60);
117
+ timeInfo = minutes <= 2
118
+ ? `Should be done soon (${parsedData.elapsed_time} elapsed)`
119
+ : `Estimated ${minutes} minutes remaining`;
120
+ }
121
+
122
+ publishRequestProgress({
123
+ requestId: this.requestId,
124
+ progress: parsedData.progress,
125
+ info: timeInfo
126
+ });
127
+ sent = true;
128
+ }
129
+ }
130
+ if (!sent) {
131
+ publishRequestProgress({
132
+ requestId: this.requestId,
133
+ info: data
134
+ });
135
+ }
125
136
  logger.debug('Data:', data);
137
+
126
138
  // Extract JSON content if message contains targetLocales
127
139
  const jsonMatch = data.match(/{[\s\S]*"targetLocales"[\s\S]*}/);
128
140
  if (jsonMatch) {