zaysrwk commited on
Commit
9b703ea
·
1 Parent(s): 6df4679

Add progress indicators and improve image enhancement functionality

Browse files

Implement asynchronous processing with progress polling for image enhancement and other features, including UI updates for progress display and improved error handling for API responses.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 064f791d-a5ee-4eab-ab49-cbb215105dc0
Replit-Commit-Checkpoint-Type: intermediate_checkpoint
Replit-Commit-Event-Id: f6a563d0-2106-4108-9f7d-27dee4df41da

Files changed (2) hide show
  1. my_ssh_key.txt +0 -0
  2. templates/index.html +125 -6
my_ssh_key.txt DELETED
File without changes
templates/index.html CHANGED
@@ -264,6 +264,40 @@
264
  to { transform: rotate(360deg); }
265
  }
266
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
267
  .error {
268
  background: rgba(255, 50, 50, 0.2);
269
  border: 1px solid #ff3232;
@@ -425,6 +459,13 @@
425
  <div class="loading" id="loading">
426
  <div class="spinner"></div>
427
  <p id="loadingText">Processing your image with AI...</p>
 
 
 
 
 
 
 
428
  <p><small>This may take a moment</small></p>
429
  </div>
430
 
@@ -482,6 +523,9 @@
482
  const downloadBtn = document.getElementById('downloadBtn');
483
  const resultBox = document.getElementById('resultBox');
484
  const resultLabel = document.getElementById('resultLabel');
 
 
 
485
 
486
  const featureTabs = document.querySelectorAll('.feature-tab');
487
  const bgcolorSelect = document.getElementById('bgcolor');
@@ -575,22 +619,91 @@
575
  hideError();
576
  }
577
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
578
  processBtn.addEventListener('click', async () => {
579
  if (!selectedFile) return;
580
 
581
  const formData = new FormData();
582
  formData.append('file', selectedFile);
583
 
584
- let endpoint = '/enhance';
585
  let params = new URLSearchParams();
586
 
587
  if (currentFeature === 'enhance') {
 
588
  const scale = document.getElementById('scale').value;
589
  params.append('scale', scale);
590
  loadingText.textContent = 'Enhancing your image with AI...';
591
  resultLabel.textContent = 'Enhanced';
592
  } else if (currentFeature === 'remove-bg') {
593
- endpoint = '/remove-background';
594
  let bgcolor = bgcolorSelect.value;
595
  if (bgcolor === 'custom') {
596
  bgcolor = document.getElementById('customColor').value;
@@ -600,13 +713,13 @@
600
  resultLabel.textContent = 'Background Removed';
601
  resultBox.classList.add('checkerboard');
602
  } else if (currentFeature === 'denoise') {
603
- endpoint = '/denoise';
604
  const strength = document.getElementById('strength').value;
605
  params.append('strength', strength);
606
  loadingText.textContent = 'Reducing noise in your image...';
607
  resultLabel.textContent = 'Denoised';
608
  } else if (currentFeature === 'docscan') {
609
- endpoint = '/docscan';
610
  const docScale = document.getElementById('docScale').value;
611
  const enhanceHd = document.getElementById('enhanceHd').value;
612
  params.append('scale', docScale);
@@ -623,6 +736,7 @@
623
  results.classList.remove('show');
624
  processBtn.disabled = true;
625
  hideError();
 
626
 
627
  try {
628
  const response = await fetch(`${endpoint}?${params.toString()}`, {
@@ -635,8 +749,13 @@
635
  throw new Error(errorData.detail || 'Processing failed');
636
  }
637
 
638
- const blob = await response.blob();
639
- const imageUrl = URL.createObjectURL(blob);
 
 
 
 
 
640
 
641
  processedImg.src = imageUrl;
642
  downloadBtn.href = imageUrl;
 
264
  to { transform: rotate(360deg); }
265
  }
266
 
267
+ .progress-container {
268
+ width: 100%;
269
+ max-width: 400px;
270
+ margin: 20px auto;
271
+ }
272
+
273
+ .progress-bar-wrapper {
274
+ background: rgba(255, 255, 255, 0.1);
275
+ border-radius: 10px;
276
+ overflow: hidden;
277
+ height: 20px;
278
+ }
279
+
280
+ .progress-bar {
281
+ height: 100%;
282
+ background: linear-gradient(90deg, #00d2ff, #3a7bd5);
283
+ border-radius: 10px;
284
+ transition: width 0.3s ease;
285
+ width: 0%;
286
+ }
287
+
288
+ .progress-text {
289
+ margin-top: 10px;
290
+ color: #888;
291
+ font-size: 0.9rem;
292
+ }
293
+
294
+ .progress-percentage {
295
+ color: #00d2ff;
296
+ font-weight: 600;
297
+ font-size: 1.1rem;
298
+ margin-bottom: 5px;
299
+ }
300
+
301
  .error {
302
  background: rgba(255, 50, 50, 0.2);
303
  border: 1px solid #ff3232;
 
459
  <div class="loading" id="loading">
460
  <div class="spinner"></div>
461
  <p id="loadingText">Processing your image with AI...</p>
462
+ <div class="progress-container">
463
+ <div class="progress-percentage" id="progressPercentage">0%</div>
464
+ <div class="progress-bar-wrapper">
465
+ <div class="progress-bar" id="progressBar"></div>
466
+ </div>
467
+ <p class="progress-text" id="progressMessage">Initializing...</p>
468
+ </div>
469
  <p><small>This may take a moment</small></p>
470
  </div>
471
 
 
523
  const downloadBtn = document.getElementById('downloadBtn');
524
  const resultBox = document.getElementById('resultBox');
525
  const resultLabel = document.getElementById('resultLabel');
526
+ const progressBar = document.getElementById('progressBar');
527
+ const progressPercentage = document.getElementById('progressPercentage');
528
+ const progressMessage = document.getElementById('progressMessage');
529
 
530
  const featureTabs = document.querySelectorAll('.feature-tab');
531
  const bgcolorSelect = document.getElementById('bgcolor');
 
619
  hideError();
620
  }
621
 
622
+ function updateProgress(progress, message) {
623
+ progressBar.style.width = `${progress}%`;
624
+ progressPercentage.textContent = `${Math.round(progress)}%`;
625
+ if (message) {
626
+ progressMessage.textContent = message;
627
+ }
628
+ }
629
+
630
+ function resetProgress() {
631
+ progressBar.style.width = '0%';
632
+ progressPercentage.textContent = '0%';
633
+ progressMessage.textContent = 'Initializing...';
634
+ }
635
+
636
+ async function pollProgress(jobId, resultUrl) {
637
+ const progressUrl = `/progress/${jobId}`;
638
+ const maxRetries = 600;
639
+ let retries = 0;
640
+
641
+ while (retries < maxRetries) {
642
+ retries++;
643
+
644
+ try {
645
+ const response = await fetch(progressUrl);
646
+ if (!response.ok) {
647
+ throw new Error('Failed to get progress');
648
+ }
649
+
650
+ const data = await response.json();
651
+ updateProgress(data.progress, data.message);
652
+
653
+ if (data.status === 'completed') {
654
+ let resultRetries = 0;
655
+ while (resultRetries < 10) {
656
+ const resultResponse = await fetch(resultUrl);
657
+
658
+ if (resultResponse.status === 202) {
659
+ resultRetries++;
660
+ await new Promise(resolve => setTimeout(resolve, 1000));
661
+ continue;
662
+ }
663
+
664
+ if (!resultResponse.ok) {
665
+ let errorMessage = 'Failed to get result';
666
+ try {
667
+ const errorData = await resultResponse.json();
668
+ errorMessage = errorData.detail || errorMessage;
669
+ } catch (e) {}
670
+ throw new Error(errorMessage);
671
+ }
672
+
673
+ const blob = await resultResponse.blob();
674
+ return URL.createObjectURL(blob);
675
+ }
676
+ throw new Error('Timed out waiting for result');
677
+ } else if (data.status === 'failed') {
678
+ throw new Error(data.error || data.message || 'Processing failed');
679
+ }
680
+
681
+ await new Promise(resolve => setTimeout(resolve, 500));
682
+ } catch (err) {
683
+ throw err;
684
+ }
685
+ }
686
+
687
+ throw new Error('Timed out waiting for processing to complete');
688
+ }
689
+
690
  processBtn.addEventListener('click', async () => {
691
  if (!selectedFile) return;
692
 
693
  const formData = new FormData();
694
  formData.append('file', selectedFile);
695
 
696
+ let endpoint = '/enhance/async';
697
  let params = new URLSearchParams();
698
 
699
  if (currentFeature === 'enhance') {
700
+ endpoint = '/enhance/async';
701
  const scale = document.getElementById('scale').value;
702
  params.append('scale', scale);
703
  loadingText.textContent = 'Enhancing your image with AI...';
704
  resultLabel.textContent = 'Enhanced';
705
  } else if (currentFeature === 'remove-bg') {
706
+ endpoint = '/remove-background/async';
707
  let bgcolor = bgcolorSelect.value;
708
  if (bgcolor === 'custom') {
709
  bgcolor = document.getElementById('customColor').value;
 
713
  resultLabel.textContent = 'Background Removed';
714
  resultBox.classList.add('checkerboard');
715
  } else if (currentFeature === 'denoise') {
716
+ endpoint = '/denoise/async';
717
  const strength = document.getElementById('strength').value;
718
  params.append('strength', strength);
719
  loadingText.textContent = 'Reducing noise in your image...';
720
  resultLabel.textContent = 'Denoised';
721
  } else if (currentFeature === 'docscan') {
722
+ endpoint = '/docscan/async';
723
  const docScale = document.getElementById('docScale').value;
724
  const enhanceHd = document.getElementById('enhanceHd').value;
725
  params.append('scale', docScale);
 
736
  results.classList.remove('show');
737
  processBtn.disabled = true;
738
  hideError();
739
+ resetProgress();
740
 
741
  try {
742
  const response = await fetch(`${endpoint}?${params.toString()}`, {
 
749
  throw new Error(errorData.detail || 'Processing failed');
750
  }
751
 
752
+ const jobData = await response.json();
753
+ const jobId = jobData.job_id;
754
+ const resultUrl = jobData.result_url;
755
+
756
+ updateProgress(5, 'Job started...');
757
+
758
+ const imageUrl = await pollProgress(jobId, resultUrl);
759
 
760
  processedImg.src = imageUrl;
761
  downloadBtn.href = imageUrl;