amit01Xindus commited on
Commit
e253ffe
·
verified ·
1 Parent(s): b9ee277

Update static/index.html

Browse files
Files changed (1) hide show
  1. static/index.html +165 -426
static/index.html CHANGED
@@ -264,448 +264,187 @@
264
  </div>
265
 
266
  <script>
267
- let currentInvoiceData = null;
268
- let currentTaskId = null;
269
- let pollingInterval = null;
270
-
271
- const uploadArea = document.getElementById('upload-area');
272
- const fileInput = document.getElementById('file-input');
273
- const fileInfo = document.getElementById('file-info');
274
- const fileName = document.getElementById('file-name');
275
- const processing = document.getElementById('processing');
276
- const resultSection = document.getElementById('result-section');
277
- const resultContent = document.getElementById('result-content');
278
- const buttonsSection = document.getElementById('buttons-section');
279
- const errorMessage = document.getElementById('error-message');
280
- const successMessage = document.getElementById('success-message');
281
- const convertJsonBtn = document.getElementById('convert-json');
282
- const convertExcelBtn = document.getElementById('convert-excel');
283
-
284
- // Add progress elements if they don't exist
285
- let progressContainer = document.getElementById('progress-container');
286
- let progressBar = document.getElementById('progress-bar');
287
- let progressText = document.getElementById('progress-text');
288
-
289
- if (!progressContainer) {
290
- // Create progress elements
291
- progressContainer = document.createElement('div');
292
- progressContainer.id = 'progress-container';
293
- progressContainer.style.cssText = `
294
- display: none;
295
- margin: 20px 0;
296
- padding: 15px;
297
- background-color: #f8f9fa;
298
- border-radius: 8px;
299
- border: 1px solid #dee2e6;
300
- `;
301
-
302
- progressBar = document.createElement('div');
303
- progressBar.id = 'progress-bar';
304
- progressBar.style.cssText = `
305
- width: 100%;
306
- height: 20px;
307
- background-color: #e9ecef;
308
- border-radius: 10px;
309
- overflow: hidden;
310
- margin-bottom: 10px;
311
- `;
312
-
313
- const progressFill = document.createElement('div');
314
- progressFill.id = 'progress-fill';
315
- progressFill.style.cssText = `
316
- height: 100%;
317
- background: linear-gradient(90deg, #007bff, #0056b3);
318
- width: 0%;
319
- transition: width 0.3s ease;
320
- border-radius: 10px;
321
- `;
322
-
323
- progressText = document.createElement('div');
324
- progressText.id = 'progress-text';
325
- progressText.style.cssText = `
326
- font-size: 14px;
327
- color: #495057;
328
- text-align: center;
329
- font-weight: 500;
330
- `;
331
-
332
- progressBar.appendChild(progressFill);
333
- progressContainer.appendChild(progressBar);
334
- progressContainer.appendChild(progressText);
335
-
336
- // Insert after processing div
337
- processing.parentNode.insertBefore(progressContainer, processing.nextSibling);
338
- }
339
-
340
- uploadArea.addEventListener('click', () => fileInput.click());
341
-
342
- uploadArea.addEventListener('dragover', (e) => {
343
- e.preventDefault();
344
- uploadArea.classList.add('dragover');
345
- });
346
-
347
- uploadArea.addEventListener('dragleave', () => {
348
- uploadArea.classList.remove('dragover');
349
- });
350
-
351
- uploadArea.addEventListener('drop', (e) => {
352
- e.preventDefault();
353
- uploadArea.classList.remove('dragover');
354
- const files = e.dataTransfer.files;
355
- if (files.length > 0) {
356
- handleFile(files[0]);
357
- }
358
- });
359
-
360
- fileInput.addEventListener('change', (e) => {
361
- if (e.target.files.length > 0) {
362
- handleFile(e.target.files[0]);
363
- }
364
- });
365
-
366
- function hideMessages() {
367
- errorMessage.style.display = 'none';
368
- successMessage.style.display = 'none';
369
- }
370
-
371
- function showError(message) {
372
- hideMessages();
373
- errorMessage.textContent = message;
374
- errorMessage.style.display = 'block';
375
- hideProcessing();
376
- }
377
-
378
- function showSuccess(message) {
379
- hideMessages();
380
- successMessage.textContent = message;
381
- successMessage.style.display = 'block';
382
- }
383
-
384
- function showProcessing() {
385
- processing.style.display = 'block';
386
- progressContainer.style.display = 'block';
387
- updateProgress(0, 'Starting upload...');
388
- }
389
-
390
- function hideProcessing() {
391
- processing.style.display = 'none';
392
- progressContainer.style.display = 'none';
393
- if (pollingInterval) {
394
- clearInterval(pollingInterval);
395
- pollingInterval = null;
396
- }
397
- }
398
-
399
- function updateProgress(percentage, message) {
400
- const progressFill = document.getElementById('progress-fill');
401
- if (progressFill) {
402
- progressFill.style.width = percentage + '%';
403
- }
404
- if (progressText) {
405
- progressText.textContent = message;
406
- }
407
- }
408
-
409
- function startPolling(taskId) {
410
- let pollCount = 0;
411
- const maxPolls = 150; // 5 minutes at 2-second intervals
412
-
413
- pollingInterval = setInterval(async () => {
414
- pollCount++;
415
-
416
- if (pollCount > maxPolls) {
417
- clearInterval(pollingInterval);
418
- hideProcessing();
419
- showError('Processing timeout. Please try again with a smaller file.');
420
- return;
421
- }
422
-
423
- try {
424
- const response = await fetch(`/status/${taskId}`);
425
-
426
- if (!response.ok) {
427
- throw new Error(`HTTP error! status: ${response.status}`);
428
- }
429
-
430
- const data = await response.json();
431
-
432
- if (data.status === 'completed') {
433
- clearInterval(pollingInterval);
434
- hideProcessing();
435
-
436
- if (data.result && data.result.success) {
437
- currentInvoiceData = data.result.data;
438
- resultContent.textContent = JSON.stringify(data.result.data, null, 2);
439
- resultSection.style.display = 'block';
440
- buttonsSection.style.display = 'block';
441
-
442
- const processingTime = data.result.processing_time ?
443
- ` (${data.result.processing_time.toFixed(1)}s)` : '';
444
- showSuccess(`Invoice processed successfully!${processingTime}`);
445
- } else {
446
- showError(data.result?.error || 'Processing failed');
447
- }
448
-
449
- } else if (data.status === 'failed') {
450
- clearInterval(pollingInterval);
451
- hideProcessing();
452
- showError(data.error || 'Processing failed');
453
-
454
- } else {
455
- // Still processing - update progress
456
- const progressPercentage = Math.min(20 + (pollCount * 2), 90);
457
- updateProgress(progressPercentage, data.progress || 'Processing...');
458
  }
459
-
460
- } catch (error) {
461
- console.error('Polling error:', error);
462
- // Don't stop polling on network errors, just log them
463
- updateProgress(null, 'Network issue, retrying...');
464
- }
465
- }, 2000); // Poll every 2 seconds
466
- }
467
-
468
- async function handleFile(file) {
469
- if (!file.name.toLowerCase().endsWith('.pdf')) {
470
- showError('Please select a PDF file only.');
471
- return;
472
- }
473
-
474
- if (file.size > 50 * 1024 * 1024) {
475
- showError('File size must be less than 50MB.');
476
- return;
477
- }
478
-
479
- fileName.textContent = file.name;
480
- fileInfo.style.display = 'block';
481
-
482
- hideMessages();
483
- resultSection.style.display = 'none';
484
- buttonsSection.style.display = 'none';
485
- showProcessing();
486
-
487
- const formData = new FormData();
488
- formData.append('file', file);
489
-
490
- try {
491
- // Determine which endpoint to use based on file size
492
- const endpoint = file.size < 1024 * 1024 ? '/upload_sync' : '/upload'; // 1MB threshold
493
-
494
- updateProgress(10, 'Uploading file...');
495
-
496
- const response = await fetch(endpoint, {
497
- method: 'POST',
498
- body: formData
499
  });
500
 
501
- if (!response.ok) {
502
- throw new Error(`HTTP error! status: ${response.status}`);
503
- }
504
-
505
- const data = await response.json();
506
-
507
- if (data.success) {
508
- if (data.task_id) {
509
- // Async processing
510
- currentTaskId = data.task_id;
511
- updateProgress(15, 'Processing started, please wait...');
512
- startPolling(data.task_id);
513
- } else {
514
- // Sync processing (small files)
515
- hideProcessing();
516
- currentInvoiceData = data.data;
517
- resultContent.textContent = JSON.stringify(data.data, null, 2);
518
- resultSection.style.display = 'block';
519
- buttonsSection.style.display = 'block';
520
-
521
- const processingTime = data.processing_time ? ` (${data.processing_time})` : '';
522
- showSuccess(`Invoice processed successfully!${processingTime}`);
523
  }
524
- } else {
525
- hideProcessing();
526
- showError(data.error || 'Failed to process the invoice.');
 
 
527
  }
528
 
529
- } catch (error) {
530
- hideProcessing();
531
- console.error('Error:', error);
 
 
532
 
533
- if (error.message.includes('timeout') || error.message.includes('fetch')) {
534
- showError('Connection timeout. Please check your internet connection and try again.');
535
- } else {
536
- showError('Network error occurred. Please try again.');
537
  }
538
- }
539
- }
540
-
541
- // Add cancel processing functionality
542
- function addCancelButton() {
543
- let cancelBtn = document.getElementById('cancel-btn');
544
- if (!cancelBtn) {
545
- cancelBtn = document.createElement('button');
546
- cancelBtn.id = 'cancel-btn';
547
- cancelBtn.textContent = 'Cancel Processing';
548
- cancelBtn.style.cssText = `
549
- margin-top: 10px;
550
- padding: 8px 16px;
551
- background-color: #dc3545;
552
- color: white;
553
- border: none;
554
- border-radius: 4px;
555
- cursor: pointer;
556
- font-size: 14px;
557
- `;
558
 
559
- cancelBtn.addEventListener('click', () => {
560
- if (pollingInterval) {
561
- clearInterval(pollingInterval);
562
- pollingInterval = null;
563
  }
564
- hideProcessing();
565
- showError('Processing cancelled by user.');
566
- });
567
-
568
- progressContainer.appendChild(cancelBtn);
569
- }
570
-
571
- cancelBtn.style.display = pollingInterval ? 'inline-block' : 'none';
572
- }
573
-
574
- // Update showProcessing to include cancel button
575
- function showProcessing() {
576
- processing.style.display = 'block';
577
- progressContainer.style.display = 'block';
578
- updateProgress(0, 'Starting upload...');
579
- addCancelButton();
580
- }
581
-
582
- convertJsonBtn.addEventListener('click', async () => {
583
- if (!currentInvoiceData) return;
584
-
585
- try {
586
- const response = await fetch('/convert_json', {
587
- method: 'POST',
588
- headers: {
589
- 'Content-Type': 'application/json',
590
- },
591
- body: JSON.stringify({
592
- invoice_data: currentInvoiceData
593
  })
594
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
595
 
596
- const data = await response.json();
597
-
598
- if (data.success) {
599
- const blob = new Blob([data.json_data], { type: 'application/json' });
600
- const url = window.URL.createObjectURL(blob);
601
- const a = document.createElement('a');
602
- a.href = url;
603
- a.download = data.filename;
604
- document.body.appendChild(a);
605
- a.click();
606
- document.body.removeChild(a);
607
- window.URL.revokeObjectURL(url);
608
- showSuccess('JSON file downloaded successfully!');
609
- } else {
610
- showError(data.error || 'Failed to convert to JSON.');
611
- }
612
- } catch (error) {
613
- showError('Network error occurred. Please try again.');
614
- console.error('Error:', error);
615
- }
616
- });
617
-
618
- convertExcelBtn.addEventListener('click', async () => {
619
- if (!currentInvoiceData) return;
620
-
621
- try {
622
- const response = await fetch('/convert_excel', {
623
- method: 'POST',
624
- headers: {
625
- 'Content-Type': 'application/json',
626
- },
627
- body: JSON.stringify({
628
- invoice_data: currentInvoiceData
629
  })
 
 
 
 
630
  });
631
 
632
- const data = await response.json();
633
-
634
- if (data.success) {
635
- const binaryString = atob(data.excel_data);
636
- const bytes = new Uint8Array(binaryString.length);
637
- for (let i = 0; i < binaryString.length; i++) {
638
- bytes[i] = binaryString.charCodeAt(i);
639
- }
640
- const blob = new Blob([bytes], {
641
- type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
642
  });
643
- const url = window.URL.createObjectURL(blob);
644
- const a = document.createElement('a');
645
- a.href = url;
646
- a.download = data.filename;
647
- document.body.appendChild(a);
648
- a.click();
649
- document.body.removeChild(a);
650
- window.URL.revokeObjectURL(url);
651
- showSuccess('Excel file downloaded successfully!');
652
- } else {
653
- showError(data.error || 'Failed to convert to Excel.');
654
- }
655
- } catch (error) {
656
- showError('Network error occurred. Please try again.');
657
- console.error('Error:', error);
658
- }
659
- });
660
-
661
- // Add some additional CSS for better UX
662
- const additionalCSS = `
663
- .upload-area.dragover {
664
- border-color: #007bff;
665
- background-color: #e7f3ff;
666
- }
667
-
668
- #progress-container {
669
- animation: fadeIn 0.3s ease-in;
670
- }
671
-
672
- @keyframes fadeIn {
673
- from { opacity: 0; transform: translateY(-10px); }
674
- to { opacity: 1; transform: translateY(0); }
675
- }
676
-
677
- #cancel-btn:hover {
678
- background-color: #c82333;
679
- }
680
-
681
- .processing-spinner {
682
- display: inline-block;
683
- width: 20px;
684
- height: 20px;
685
- border: 3px solid #f3f3f3;
686
- border-top: 3px solid #007bff;
687
- border-radius: 50%;
688
- animation: spin 1s linear infinite;
689
- margin-right: 10px;
690
- }
691
-
692
- @keyframes spin {
693
- 0% { transform: rotate(0deg); }
694
- 100% { transform: rotate(360deg); }
695
- }
696
- `;
697
-
698
- // Add CSS to head
699
- const styleSheet = document.createElement('style');
700
- styleSheet.textContent = additionalCSS;
701
- document.head.appendChild(styleSheet);
702
-
703
- // Add spinner to processing text
704
- if (processing) {
705
- const spinner = document.createElement('div');
706
- spinner.className = 'processing-spinner';
707
- processing.insertBefore(spinner, processing.firstChild);
708
- }
709
  </script>
710
  </body>
711
  </html>
 
264
  </div>
265
 
266
  <script>
267
+ let currentInvoiceData = null;
268
+
269
+ const uploadArea = document.getElementById('upload-area');
270
+ const fileInput = document.getElementById('file-input');
271
+ const fileInfo = document.getElementById('file-info');
272
+ const fileName = document.getElementById('file-name');
273
+ const processing = document.getElementById('processing');
274
+ const resultSection = document.getElementById('result-section');
275
+ const resultContent = document.getElementById('result-content');
276
+ const buttonsSection = document.getElementById('buttons-section');
277
+ const errorMessage = document.getElementById('error-message');
278
+ const successMessage = document.getElementById('success-message');
279
+ const convertJsonBtn = document.getElementById('convert-json');
280
+ const convertExcelBtn = document.getElementById('convert-excel');
281
+
282
+ uploadArea.addEventListener('click', () => fileInput.click());
283
+
284
+ uploadArea.addEventListener('dragover', (e) => {
285
+ e.preventDefault();
286
+ uploadArea.classList.add('dragover');
287
+ });
288
+
289
+ uploadArea.addEventListener('dragleave', () => {
290
+ uploadArea.classList.remove('dragover');
291
+ });
292
+
293
+ uploadArea.addEventListener('drop', (e) => {
294
+ e.preventDefault();
295
+ uploadArea.classList.remove('dragover');
296
+ const files = e.dataTransfer.files;
297
+ if (files.length > 0) {
298
+ handleFile(files[0]);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
299
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
300
  });
301
 
302
+ fileInput.addEventListener('change', (e) => {
303
+ if (e.target.files.length > 0) {
304
+ handleFile(e.target.files[0]);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
305
  }
306
+ });
307
+
308
+ function hideMessages() {
309
+ errorMessage.style.display = 'none';
310
+ successMessage.style.display = 'none';
311
  }
312
 
313
+ function showError(message) {
314
+ hideMessages();
315
+ errorMessage.textContent = message;
316
+ errorMessage.style.display = 'block';
317
+ }
318
 
319
+ function showSuccess(message) {
320
+ hideMessages();
321
+ successMessage.textContent = message;
322
+ successMessage.style.display = 'block';
323
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
324
 
325
+ function handleFile(file) {
326
+ if (!file.name.toLowerCase().endsWith('.pdf')) {
327
+ showError('Please select a PDF file only.');
328
+ return;
329
  }
330
+
331
+ if (file.size > 50 * 1024 * 1024) {
332
+ showError('File size must be less than 50MB.');
333
+ return;
334
+ }
335
+
336
+ fileName.textContent = file.name;
337
+ fileInfo.style.display = 'block';
338
+
339
+ hideMessages();
340
+ resultSection.style.display = 'none';
341
+ buttonsSection.style.display = 'none';
342
+ processing.style.display = 'block';
343
+
344
+ const formData = new FormData();
345
+ formData.append('file', file);
346
+
347
+ fetch('/upload', {
348
+ method: 'POST',
349
+ body: formData
 
 
 
 
 
 
 
 
 
350
  })
351
+ .then(response => response.json())
352
+ .then(data => {
353
+ processing.style.display = 'none';
354
+
355
+ if (data.success) {
356
+ currentInvoiceData = data.data;
357
+ resultContent.textContent = JSON.stringify(data.data, null, 2);
358
+ resultSection.style.display = 'block';
359
+ buttonsSection.style.display = 'block';
360
+ showSuccess('Invoice processed successfully!');
361
+ } else {
362
+ showError(data.error || 'Failed to process the invoice.');
363
+ }
364
+ })
365
+ .catch(error => {
366
+ processing.style.display = 'none';
367
+ showError('Network error occurred. Please try again.');
368
+ console.error('Error:', error);
369
+ });
370
+ }
371
 
372
+ convertJsonBtn.addEventListener('click', () => {
373
+ if (!currentInvoiceData) return;
374
+
375
+ fetch('/convert_json', {
376
+ method: 'POST',
377
+ headers: {
378
+ 'Content-Type': 'application/json',
379
+ },
380
+ body: JSON.stringify({
381
+ invoice_data: currentInvoiceData
382
+ })
383
+ })
384
+ .then(response => response.json())
385
+ .then(data => {
386
+ if (data.success) {
387
+ const blob = new Blob([data.json_data], { type: 'application/json' });
388
+ const url = window.URL.createObjectURL(blob);
389
+ const a = document.createElement('a');
390
+ a.href = url;
391
+ a.download = data.filename;
392
+ document.body.appendChild(a);
393
+ a.click();
394
+ document.body.removeChild(a);
395
+ window.URL.revokeObjectURL(url);
396
+ showSuccess('JSON file downloaded successfully!');
397
+ } else {
398
+ showError(data.error || 'Failed to convert to JSON.');
399
+ }
 
 
 
 
 
400
  })
401
+ .catch(error => {
402
+ showError('Network error occurred. Please try again.');
403
+ console.error('Error:', error);
404
+ });
405
  });
406
 
407
+ convertExcelBtn.addEventListener('click', () => {
408
+ if (!currentInvoiceData) return;
409
+
410
+ fetch('/convert_excel', {
411
+ method: 'POST',
412
+ headers: {
413
+ 'Content-Type': 'application/json',
414
+ },
415
+ body: JSON.stringify({
416
+ invoice_data: currentInvoiceData
417
+ })
418
+ })
419
+ .then(response => response.json())
420
+ .then(data => {
421
+ if (data.success) {
422
+ const binaryString = atob(data.excel_data);
423
+ const bytes = new Uint8Array(binaryString.length);
424
+ for (let i = 0; i < binaryString.length; i++) {
425
+ bytes[i] = binaryString.charCodeAt(i);
426
+ }
427
+ const blob = new Blob([bytes], {
428
+ type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
429
+ });
430
+ const url = window.URL.createObjectURL(blob);
431
+ const a = document.createElement('a');
432
+ a.href = url;
433
+ a.download = data.filename;
434
+ document.body.appendChild(a);
435
+ a.click();
436
+ document.body.removeChild(a);
437
+ window.URL.revokeObjectURL(url);
438
+ showSuccess('Excel file downloaded successfully!');
439
+ } else {
440
+ showError(data.error || 'Failed to convert to Excel.');
441
+ }
442
+ })
443
+ .catch(error => {
444
+ showError('Network error occurred. Please try again.');
445
+ console.error('Error:', error);
446
  });
447
+ });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
448
  </script>
449
  </body>
450
  </html>