@aj-archipelago/cortex 1.3.7 → 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);
@@ -82,16 +82,35 @@ export default function Chat({
82
82
  logger.log('Stopping conversation');
83
83
  const wavRecorder = wavRecorderRef.current;
84
84
  const wavStreamPlayer = wavStreamPlayerRef.current;
85
+ const socket = socketRef.current;
85
86
 
86
- if (wavRecorder.getStatus() === "recording") {
87
- await wavRecorder.end();
88
- await wavStreamPlayer.interrupt();
89
- await SoundEffects.playDisconnect();
90
- socketRef.current.emit('conversationCompleted');
91
- socketRef.current.removeAllListeners();
92
- socketRef.current.disconnect();
87
+ try {
88
+ // First stop recording and audio playback
89
+ if (wavRecorder.getStatus() === "recording") {
90
+ await wavRecorder.end();
91
+ }
92
+ if (wavStreamPlayer) {
93
+ await wavStreamPlayer.interrupt();
94
+ }
95
+
96
+ // Clean up socket connection first
97
+ if (socket) {
98
+ // Only emit if we're still connected
99
+ if (socket.connected) {
100
+ socket.emit('conversationCompleted');
101
+ // Wait a bit to ensure the message is sent
102
+ await new Promise(resolve => setTimeout(resolve, 100));
103
+ }
104
+ socket.removeAllListeners();
105
+ socket.disconnect();
106
+ // Create a new socket instance to ensure clean state
107
+ socketRef.current = io(`/?userId=${userId}&userName=${userName}&aiName=${aiName}&voice=${voice}&aiStyle=${aiStyle}&language=${language}`, {
108
+ autoConnect: false,
109
+ reconnection: false
110
+ });
111
+ }
93
112
 
94
- // Clean up audio nodes
113
+ // Then clean up audio nodes
95
114
  if (sourceNodeRef.current) {
96
115
  sourceNodeRef.current.disconnect();
97
116
  sourceNodeRef.current = null;
@@ -109,15 +128,36 @@ export default function Chat({
109
128
  wavRecorderRef.current = new WavRecorder({sampleRate: 24000});
110
129
  wavStreamPlayerRef.current = new WavStreamPlayer({sampleRate: 24000});
111
130
 
131
+ // Play disconnect sound last
132
+ await SoundEffects.playDisconnect();
133
+
134
+ // Reset state
135
+ setIsRecording(false);
136
+ setIsMuted(false);
137
+ setImageUrls([]);
138
+ setIsAudioPlaying(false);
139
+ } catch (error) {
140
+ logger.error('Error stopping conversation:', error);
141
+ // Even if there's an error, try to reset critical state
112
142
  setIsRecording(false);
113
- setIsMuted(false); // Reset mute state
114
- setImageUrls([]); // Clear images on disconnect
143
+ setIsAudioPlaying(false);
115
144
  }
116
- }, []);
145
+ }, [userId, userName, aiName, voice, aiStyle, language]);
117
146
 
118
147
  const startConversation = useCallback(() => {
119
148
  logger.log('Starting conversation');
120
149
 
150
+ // Clean up any existing socket connection first
151
+ if (socketRef.current?.connected) {
152
+ socketRef.current.disconnect();
153
+ }
154
+
155
+ // Create a new socket instance
156
+ socketRef.current = io(`/?userId=${userId}&userName=${userName}&aiName=${aiName}&voice=${voice}&aiStyle=${aiStyle}&language=${language}`, {
157
+ autoConnect: false,
158
+ timeout: 10000 // 10 second connection timeout
159
+ });
160
+
121
161
  const socket = socketRef.current;
122
162
 
123
163
  // Remove ALL existing listeners before adding new ones