ziadmostafa commited on
Commit
c513e86
·
1 Parent(s): a71db49

Replace with updated NoteGenie version

Browse files
Files changed (1) hide show
  1. static/js/main.js +143 -111
static/js/main.js CHANGED
@@ -444,6 +444,7 @@ document.addEventListener('DOMContentLoaded', function() {
444
  // Close any existing event source
445
  if (eventSource) {
446
  eventSource.close();
 
447
  }
448
 
449
  // Keep track of when we should update the preview (not on every tiny chunk)
@@ -456,7 +457,12 @@ document.addEventListener('DOMContentLoaded', function() {
456
  // Make sure notebook is in proper format before sending
457
  const notebookToSend = typeof notebook === 'string' ? JSON.parse(notebook) : notebook;
458
 
459
- console.log('Sending notebook for editing:', notebookToSend); // Debug log
 
 
 
 
 
460
 
461
  // First, send the notebook data to the server so it's available in the session
462
  fetch('/prepare_edit_notebook', {
@@ -472,7 +478,7 @@ document.addEventListener('DOMContentLoaded', function() {
472
  })
473
  .then(response => {
474
  if (!response.ok) {
475
- throw new Error(`Server error: ${response.status}`);
476
  }
477
  return response.json();
478
  })
@@ -498,135 +504,161 @@ document.addEventListener('DOMContentLoaded', function() {
498
  headers['X-API-Key'] = backupApiKey;
499
  }
500
 
501
- // Now create a new event source for editing with the API key included in both URL and headers
502
- eventSource = createEventSourceWithHeaders(`/edit_notebook?${urlParams.toString()}`, headers);
503
 
504
- // Track the last time we got a chunk - for timeout detection
505
- let lastChunkTime = Date.now();
506
- const CONNECTION_TIMEOUT = 30000; // 30 seconds without data = timeout
507
-
508
- // Start a monitoring timer to detect stalled connections
509
- const connectionTimer = setInterval(() => {
510
- if (Date.now() - lastChunkTime > CONNECTION_TIMEOUT) {
511
- clearInterval(connectionTimer);
512
- if (eventSource) {
513
- console.log("Connection timed out - closing event source");
514
- eventSource.close();
515
- eventSource = null;
516
-
517
- // Process what we've got so far
518
- updateAiMessage(aiMessageId, "**NoteGenie:** Edit processing timed out, but I'll use what I've received so far.");
519
- processNotebookResponse(aiResponseText);
520
- setGeneratingState(false);
521
-
522
- // Switch back to generate mode
523
- setMode('generate');
524
- }
525
- }
526
- }, 5000); // Check every 5 seconds
527
-
528
- eventSource.onmessage = function(event) {
529
- // Update our last-activity timestamp
530
- lastChunkTime = Date.now();
531
 
532
- try {
533
- const data = JSON.parse(event.data);
534
-
535
- // Handle errors sent from the server
536
- if (data.error) {
537
- console.error("Server error:", data.error);
538
- updateAiMessage(aiMessageId, `**Error:** ${data.error}`);
539
-
540
- // Try to salvage what we have so far
541
- if (aiResponseText && (aiResponseText.includes('MARKDOWN CELL') || aiResponseText.includes('CODE CELL'))) {
 
 
 
 
 
542
  processNotebookResponse(aiResponseText);
 
 
 
 
543
  }
544
-
545
- eventSource.close();
546
- eventSource = null;
547
- setGeneratingState(false);
548
- clearInterval(connectionTimer);
549
-
550
- // Switch back to generate mode
551
- setMode('generate');
552
- return;
553
  }
 
 
 
 
 
 
 
 
 
554
 
555
- if (data.chunk) {
556
- aiResponseText += data.chunk;
557
 
558
- // Extract notebook info as soon as it's available, similar to generate function
559
- const nameMatch = aiResponseText.match(/NOTEBOOK_NAME:?\s*(.+?)(?:\n|$)/);
560
- const descMatch = aiResponseText.match(/NOTEBOOK_DESCRIPTION:?\s*(.+?)(?:\n|$)/);
561
-
562
- if (nameMatch && nameMatch[1].trim()) {
563
- // Update notebook title immediately when found
564
- notebookTitleEl.textContent = nameMatch[1].trim();
 
 
 
 
 
 
 
 
 
 
 
565
  }
566
 
567
- if (descMatch && descMatch[1].trim()) {
568
- // Update AI message with the actual description from the edited notebook
569
- updateAiMessage(aiMessageId, `**NoteGenie:** ${descMatch[1].trim()}`);
570
- } else {
571
- // Show a simple editing message while waiting for description
572
- updateAiMessage(aiMessageId, "**NoteGenie:** Updating notebook based on your edit request...");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
573
  }
574
 
575
- // Update preview periodically during streaming, just like in generate function
576
- const now = Date.now();
577
- if (now - lastPreviewUpdate > PREVIEW_UPDATE_INTERVAL) {
578
- lastPreviewUpdate = now;
 
579
 
580
- // Only try to update preview if we have meaningful content
581
- if (aiResponseText.includes('MARKDOWN CELL') || aiResponseText.includes('CODE CELL')) {
582
- updateNotebookPreviewDuringStream(aiResponseText);
583
- }
 
 
 
 
 
 
 
 
 
584
  }
 
 
585
  }
 
 
 
 
 
586
 
587
- if (data.done) {
 
 
 
 
 
 
 
588
  eventSource.close();
589
  eventSource = null;
590
- clearInterval(connectionTimer);
591
-
592
- // Process the complete response for final rendering
 
 
 
 
 
593
  processNotebookResponse(aiResponseText);
594
- setGeneratingState(false);
595
-
596
- // Get the final description for the AI message
597
- const finalDescMatch = aiResponseText.match(/NOTEBOOK_DESCRIPTION:?\s*(.+?)(?=\n\s*---|\n\s*$|$)/);
598
- const finalDesc = finalDescMatch ? finalDescMatch[1].trim() : "I've updated the notebook based on your edit request.";
599
-
600
- // Update AI message with final description
601
- updateAiMessage(aiMessageId, `**NoteGenie:** ${finalDesc}`);
602
-
603
- // Switch back to generate mode
604
- setMode('generate');
605
  }
606
- } catch (error) {
607
- console.error('Error parsing event data:', error, event.data);
608
- }
609
- };
610
-
611
- eventSource.onerror = function(err) {
612
- console.error('EventSource error:', err);
613
- eventSource.close();
614
- eventSource = null;
615
- clearInterval(connectionTimer);
616
-
617
- // Try to salvage what we have so far
618
- if (aiResponseText && (aiResponseText.includes('MARKDOWN CELL') || aiResponseText.includes('CODE CELL'))) {
619
- updateAiMessage(aiMessageId, '**Warning:** Connection issue occurred but I\'ll try to process what I received so far.');
620
- processNotebookResponse(aiResponseText);
621
- } else {
622
- updateAiMessage(aiMessageId, '**Error:** Failed to edit notebook. ' + (err.message || 'Unknown error'));
623
- }
624
-
625
  setGeneratingState(false);
626
-
627
- // Switch back to generate mode
628
- setMode('generate');
629
- };
630
  } else {
631
  throw new Error(data.message || 'Failed to prepare notebook for editing');
632
  }
 
444
  // Close any existing event source
445
  if (eventSource) {
446
  eventSource.close();
447
+ eventSource = null;
448
  }
449
 
450
  // Keep track of when we should update the preview (not on every tiny chunk)
 
457
  // Make sure notebook is in proper format before sending
458
  const notebookToSend = typeof notebook === 'string' ? JSON.parse(notebook) : notebook;
459
 
460
+ // Debug logging to help diagnose issues
461
+ console.log('Notebook edit request:', {
462
+ cellCount: notebookToSend.cells.length,
463
+ promptLength: editPrompt.length,
464
+ model: modelName
465
+ });
466
 
467
  // First, send the notebook data to the server so it's available in the session
468
  fetch('/prepare_edit_notebook', {
 
478
  })
479
  .then(response => {
480
  if (!response.ok) {
481
+ throw new Error(`Server error (${response.status}): ${response.statusText}`);
482
  }
483
  return response.json();
484
  })
 
504
  headers['X-API-Key'] = backupApiKey;
505
  }
506
 
507
+ console.log('Starting EventSource for edit with headers:', Object.keys(headers).length > 0 ? 'Headers present' : 'No headers');
 
508
 
509
+ // Now create a new event source for editing with the API key included in both URL and headers
510
+ try {
511
+ eventSource = createEventSourceWithHeaders(`/edit_notebook?${urlParams.toString()}`, headers);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
512
 
513
+ // Track the last time we got a chunk - for timeout detection
514
+ let lastChunkTime = Date.now();
515
+ const CONNECTION_TIMEOUT = 30000; // 30 seconds without data = timeout
516
+
517
+ // Start a monitoring timer to detect stalled connections
518
+ const connectionTimer = setInterval(() => {
519
+ if (Date.now() - lastChunkTime > CONNECTION_TIMEOUT) {
520
+ clearInterval(connectionTimer);
521
+ if (eventSource) {
522
+ console.log("Connection timed out - closing event source");
523
+ eventSource.close();
524
+ eventSource = null;
525
+
526
+ // Process what we've got so far
527
+ updateAiMessage(aiMessageId, "**NoteGenie:** Edit processing timed out, but I'll use what I've received so far.");
528
  processNotebookResponse(aiResponseText);
529
+ setGeneratingState(false);
530
+
531
+ // Switch back to generate mode
532
+ setMode('generate');
533
  }
 
 
 
 
 
 
 
 
 
534
  }
535
+ }, 5000); // Check every 5 seconds
536
+
537
+ eventSource.onopen = function(event) {
538
+ console.log('EventSource connection opened for edit');
539
+ };
540
+
541
+ eventSource.onmessage = function(event) {
542
+ // Update our last-activity timestamp
543
+ lastChunkTime = Date.now();
544
 
545
+ try {
546
+ const data = JSON.parse(event.data);
547
 
548
+ // Handle errors sent from the server
549
+ if (data.error) {
550
+ console.error("Server error during edit:", data.error);
551
+ updateAiMessage(aiMessageId, `**Error:** ${data.error}`);
552
+
553
+ // Try to salvage what we have so far
554
+ if (aiResponseText && (aiResponseText.includes('MARKDOWN CELL') || aiResponseText.includes('CODE CELL'))) {
555
+ processNotebookResponse(aiResponseText);
556
+ }
557
+
558
+ eventSource.close();
559
+ eventSource = null;
560
+ setGeneratingState(false);
561
+ clearInterval(connectionTimer);
562
+
563
+ // Switch back to generate mode
564
+ setMode('generate');
565
+ return;
566
  }
567
 
568
+ if (data.chunk) {
569
+ aiResponseText += data.chunk;
570
+
571
+ // Extract notebook info as soon as it's available, similar to generate function
572
+ const nameMatch = aiResponseText.match(/NOTEBOOK_NAME:?\s*(.+?)(?:\n|$)/);
573
+ const descMatch = aiResponseText.match(/NOTEBOOK_DESCRIPTION:?\s*(.+?)(?:\n|$)/);
574
+
575
+ if (nameMatch && nameMatch[1].trim()) {
576
+ // Update notebook title immediately when found
577
+ notebookTitleEl.textContent = nameMatch[1].trim();
578
+ }
579
+
580
+ if (descMatch && descMatch[1].trim()) {
581
+ // Update AI message with the actual description from the edited notebook
582
+ updateAiMessage(aiMessageId, `**NoteGenie:** ${descMatch[1].trim()}`);
583
+ } else {
584
+ // Show a simple editing message while waiting for description
585
+ updateAiMessage(aiMessageId, "**NoteGenie:** Updating notebook based on your edit request...");
586
+ }
587
+
588
+ // Update preview periodically during streaming, just like in generate function
589
+ const now = Date.now();
590
+ if (now - lastPreviewUpdate > PREVIEW_UPDATE_INTERVAL) {
591
+ lastPreviewUpdate = now;
592
+
593
+ // Only try to update preview if we have meaningful content
594
+ if (aiResponseText.includes('MARKDOWN CELL') || aiResponseText.includes('CODE CELL')) {
595
+ updateNotebookPreviewDuringStream(aiResponseText);
596
+ }
597
+ }
598
  }
599
 
600
+ if (data.done) {
601
+ console.log('Edit completed successfully');
602
+ eventSource.close();
603
+ eventSource = null;
604
+ clearInterval(connectionTimer);
605
 
606
+ // Process the complete response for final rendering
607
+ processNotebookResponse(aiResponseText);
608
+ setGeneratingState(false);
609
+
610
+ // Get the final description for the AI message
611
+ const finalDescMatch = aiResponseText.match(/NOTEBOOK_DESCRIPTION:?\s*(.+?)(?=\n\s*---|\n\s*$|$)/);
612
+ const finalDesc = finalDescMatch ? finalDescMatch[1].trim() : "I've updated the notebook based on your edit request.";
613
+
614
+ // Update AI message with final description
615
+ updateAiMessage(aiMessageId, `**NoteGenie:** ${finalDesc}`);
616
+
617
+ // Switch back to generate mode
618
+ setMode('generate');
619
  }
620
+ } catch (error) {
621
+ console.error('Error parsing event data:', error, event.data);
622
  }
623
+ };
624
+
625
+ eventSource.onerror = function(err) {
626
+ // More detailed error logging
627
+ console.error('EventSource error during edit:', err);
628
 
629
+ // Get any status text or error message if available
630
+ let errorMessage = 'Failed to connect to edit service';
631
+ if (err instanceof Event && err.target && err.target.status) {
632
+ errorMessage += ` (Status: ${err.target.status})`;
633
+ }
634
+
635
+ // Close and clean up event source
636
+ if (eventSource) {
637
  eventSource.close();
638
  eventSource = null;
639
+ }
640
+
641
+ // Clear any timers
642
+ clearInterval(connectionTimer);
643
+
644
+ // Try to salvage what we have so far
645
+ if (aiResponseText && (aiResponseText.includes('MARKDOWN CELL') || aiResponseText.includes('CODE CELL'))) {
646
+ updateAiMessage(aiMessageId, '**Warning:** Connection issue occurred but I\'ll try to process what I received so far.');
647
  processNotebookResponse(aiResponseText);
648
+ } else {
649
+ updateAiMessage(aiMessageId, `**Error:** Failed to edit notebook. ${errorMessage}`);
 
 
 
 
 
 
 
 
 
650
  }
651
+
652
+ setGeneratingState(false);
653
+
654
+ // Switch back to generate mode
655
+ setMode('generate');
656
+ };
657
+ } catch (e) {
658
+ console.error('Error creating EventSource:', e);
659
+ updateAiMessage(aiMessageId, `**Error:** Could not establish connection for editing: ${e.message}`);
 
 
 
 
 
 
 
 
 
 
660
  setGeneratingState(false);
661
+ }
 
 
 
662
  } else {
663
  throw new Error(data.message || 'Failed to prepare notebook for editing');
664
  }