datafreak commited on
Commit
b62495b
Β·
verified Β·
1 Parent(s): dcd1c9e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +570 -314
app.py CHANGED
@@ -13,6 +13,13 @@ import json
13
  # Load environment variables
14
  load_dotenv()
15
 
 
 
 
 
 
 
 
16
  # Validate required environment variables
17
  required_env_vars = ["PINECONE_API_KEY"]
18
  missing_vars = [var for var in required_env_vars if not os.getenv(var)]
@@ -458,344 +465,593 @@ def finish_processing():
458
  """Show processing finished status"""
459
  return "βœ… **Processing completed successfully!**"
460
 
461
- # Create Gradio interface
462
- with gr.Blocks(
463
- title="πŸ“„ Tax Document Ingestion System",
464
- theme=gr.themes.Soft(),
465
- css="""
466
- .gradio-container {
467
- max-width: 1400px !important;
468
- margin: auto;
469
- }
470
- .upload-container {
471
- border: 2px dashed #4CAF50;
472
- border-radius: 10px;
473
- padding: 20px;
474
- text-align: center;
475
- background-color: #f8f9fa;
476
- }
477
- .delete-container {
478
- border: 2px dashed #f44336;
479
- border-radius: 10px;
480
- padding: 20px;
481
- background-color: #ffebee;
482
- }
483
- .tab-nav {
484
- margin-bottom: 20px;
485
- }
486
- """
487
- ) as app:
488
-
489
- gr.Markdown(
490
  """
491
- # πŸ“„ Tax Document Ingestion System
492
-
493
- Upload, manage, and delete documents in the Pinecone Assistant for GST Minutes processing.
494
 
495
- ## πŸš€ Features:
496
- - βœ… **Multiple file upload** - Select and upload multiple documents at once
497
- - 🏷️ **Metadata tagging** - Add sections, keywords, and descriptions
498
- - πŸ”„ **Batch processing** - All files processed with individual metadata
499
- - πŸ—‘οΈ **File deletion** - Delete multiple files by selecting from dropdown
500
- - πŸ“Š **File management** - View uploaded files with timestamps and metadata
501
- - πŸ“‹ **Detailed reporting** - See success/failure status for each operation
502
-
503
- ---
504
- """
505
- )
506
-
507
- # Create tabs for different functionalities
508
- with gr.Tabs() as tabs:
509
-
510
- # Tab 1: Upload Documents
511
- with gr.TabItem("πŸ“€ Upload Documents", id="upload_tab"):
512
- with gr.Row():
513
- with gr.Column(scale=1):
514
- gr.Markdown("### πŸ“ **File Upload**")
515
- files_input = gr.File(
516
- label="Select Documents (Max 10 files)",
517
- file_count="multiple",
518
- file_types=[".pdf", ".doc", ".docx", ".txt"],
519
- elem_classes=["upload-container"]
520
- )
521
-
522
- with gr.Column(scale=1):
523
- gr.Markdown("### 🏷️ **Document Metadata (Individual for Each File)**")
524
- gr.Markdown("*Upload files first, then metadata fields will appear for each document*")
525
-
526
- # Dynamic metadata fields container
527
- with gr.Column() as metadata_container:
528
- # Create 30 text fields (enough for 10 files with 3 fields each)
529
- metadata_fields = []
530
- for i in range(30):
531
- field = gr.Textbox(
532
- label=f"Field {i}",
533
- placeholder="",
534
- visible=False,
535
- lines=2
536
- )
537
- metadata_fields.append(field)
538
-
539
- with gr.Row():
540
- with gr.Column(scale=1):
541
- upload_btn = gr.Button(
542
- "πŸš€ Upload Documents to Pinecone Assistant",
543
- variant="primary",
544
- size="lg"
545
- )
546
-
547
- with gr.Column(scale=1):
548
- clear_btn = gr.Button(
549
- "πŸ—‘οΈ Clear Form",
550
- variant="secondary",
551
- size="lg"
552
- )
553
 
554
- # Processing status indicator
555
- with gr.Row():
556
- processing_status = gr.Markdown(
557
- value="🟒 **Ready to process documents**",
558
- visible=True
559
- )
560
 
561
- gr.Markdown("---")
 
 
 
 
 
 
562
 
563
- # Results section
564
- with gr.Row():
565
- with gr.Column():
566
- status_output = gr.Markdown(
567
- label="πŸ“Š Upload Status",
568
- value="*Ready to upload documents...*"
569
- )
570
 
571
- with gr.Row():
572
- with gr.Column():
573
- results_output = gr.Markdown(
574
- label="πŸ“‹ Detailed Results",
575
- value="",
576
- max_height=400 # Add height limit for scrolling
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
577
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
578
 
579
- # Tab 2: Delete Documents
580
- with gr.TabItem("πŸ—‘οΈ Delete Documents", id="delete_tab"):
581
- gr.Markdown("### πŸ—‘οΈ **Delete Multiple Documents**")
582
- gr.Markdown("Select multiple files from the dropdown to delete them from the Pinecone Assistant.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
583
 
584
- with gr.Row():
585
- with gr.Column(scale=2):
586
- file_dropdown = gr.Dropdown(
587
- label="πŸ“‹ Select Files to Delete (Multiple Selection)",
588
- choices=[],
589
- multiselect=True,
590
- interactive=False,
591
- elem_classes=["delete-container"]
592
- )
593
-
594
- with gr.Column(scale=1):
595
- refresh_dropdown_btn = gr.Button(
596
- "πŸ”„ Refresh File List",
597
- variant="secondary",
598
  size="lg"
599
  )
600
-
601
- with gr.Row():
602
- with gr.Column(scale=1):
603
- delete_btn = gr.Button(
604
- "πŸ—‘οΈ Delete Selected Files",
605
- variant="stop",
606
- size="lg"
607
  )
608
-
609
- with gr.Column(scale=1):
610
- clear_delete_btn = gr.Button(
611
- "β†Ί Clear Selection",
 
 
 
612
  variant="secondary",
613
- size="lg"
614
  )
615
-
616
- gr.Markdown("---")
617
-
618
- # Delete results section
619
- with gr.Row():
620
- with gr.Column():
621
- delete_status_output = gr.Markdown(
622
- label="πŸ“Š Deletion Status",
623
- value="*Select files to delete...*"
624
  )
625
-
626
- with gr.Row():
627
- with gr.Column():
628
- delete_results_output = gr.Markdown(
629
- label="πŸ—‘οΈ Deletion Results",
630
- value="",
631
- max_height=400
632
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
633
 
634
- # Tab 3: View Uploaded Files
635
- with gr.TabItem("πŸ“‹ View Uploaded Files", id="view_tab"):
636
- gr.Markdown("### πŸ“‹ **Uploaded Files Management**")
637
- gr.Markdown("View all files currently uploaded to the Pinecone Assistant with their metadata and timestamps.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
638
 
639
- with gr.Row():
640
- refresh_btn = gr.Button(
641
- "πŸ”„ Fetch Files",
642
- variant="primary",
643
- size="lg"
644
- )
645
 
646
- # File list status
647
- with gr.Row():
648
- file_list_status = gr.Markdown(
649
- value="🟑 **Click 'Fetch Files' to load uploaded files**",
650
- visible=True
651
- )
652
 
653
- gr.Markdown("---")
 
 
 
 
654
 
655
- # Pagination controls
656
- with gr.Row():
657
- prev_btn = gr.Button(
658
- "⬅️ Previous 100",
659
- variant="secondary",
660
- visible=False
661
- )
662
- pagination_info = gr.Markdown(
663
- value="πŸ“„ Page 1 of 1 | Total: 0 files",
664
- elem_classes=["pagination-info"]
665
- )
666
- next_btn = gr.Button(
667
- "Next 100 ➑️",
668
- variant="secondary",
669
- visible=False
670
- )
671
 
672
- # File list results
673
- with gr.Row():
674
- with gr.Column(scale=1):
675
- file_summary = gr.Markdown(
676
- label="πŸ“Š Files Summary",
677
- value="*Click refresh to load file summary...*"
678
- )
679
 
680
- with gr.Row():
681
- with gr.Column():
682
- file_details = gr.Markdown(
683
- label="πŸ“‹ File Details",
684
- value="*Click refresh to load file details...*",
685
- max_height=600 # Add height limit for scrolling
686
- )
687
-
688
- # Event handlers for Upload tab
689
-
690
- # Update metadata fields when files are uploaded
691
- files_input.change(
692
- fn=update_metadata_fields,
693
- inputs=[files_input],
694
- outputs=metadata_fields
695
- )
696
-
697
- # Show processing status when upload starts
698
- upload_btn.click(
699
- fn=start_processing,
700
- outputs=[processing_status]
701
- ).then(
702
- fn=process_files_with_progress,
703
- inputs=[files_input] + metadata_fields,
704
- outputs=[status_output, results_output, processing_status]
705
- )
706
-
707
- clear_btn.click(
708
- fn=clear_form,
709
- outputs=[files_input] + metadata_fields + [status_output, results_output, processing_status]
710
- )
711
-
712
- # Event handlers for Delete tab
713
-
714
- # Refresh dropdown with current files
715
- refresh_dropdown_btn.click(
716
- fn=refresh_delete_dropdown,
717
- outputs=[file_dropdown]
718
- )
719
-
720
- # Delete selected files
721
- delete_btn.click(
722
- fn=delete_selected_files,
723
- inputs=[file_dropdown],
724
- outputs=[delete_status_output, delete_results_output]
725
- )
726
-
727
- # Clear delete form
728
- clear_delete_btn.click(
729
- fn=clear_delete_form,
730
- outputs=[file_dropdown, delete_status_output, delete_results_output]
731
- )
732
-
733
- # Event handlers for View Files tab
734
-
735
- # Fetch files - load page 1
736
- refresh_btn.click(
737
- fn=refresh_file_list,
738
- outputs=[file_list_status]
739
- ).then(
740
- fn=list_uploaded_files_paginated,
741
- inputs=[],
742
- outputs=[file_summary, file_details, pagination_info, prev_btn, next_btn]
743
- )
744
-
745
- # Next page button
746
- next_btn.click(
747
- fn=load_next_page,
748
- inputs=[pagination_info],
749
- outputs=[file_summary, file_details, pagination_info, prev_btn, next_btn]
750
- )
751
-
752
- # Previous page button
753
- prev_btn.click(
754
- fn=load_prev_page,
755
- inputs=[pagination_info],
756
- outputs=[file_summary, file_details, pagination_info, prev_btn, next_btn]
757
- )
758
 
759
- # Footer
760
- gr.Markdown(
761
- """
762
- ---
763
-
764
- ### πŸ’‘ **Usage Tips:**
765
-
766
- **Upload Documents:**
767
- - Select up to 10 PDF, DOC, DOCX, or TXT files at once
768
- - Upload files first, then fill individual metadata for each document
769
- - Each file gets its own sections, keywords, and description
770
- - Check the results section for upload status
771
-
772
- **Delete Documents:**
773
- - Click 'Refresh File List' to load current files in dropdown
774
- - Select multiple files using the dropdown (supports multi-select)
775
- - Click 'Delete Selected Files' to remove them permanently
776
- - View deletion results for success/failure status
777
-
778
- **View Uploaded Files:**
779
- - Click 'Fetch Files' to see all uploaded files
780
- - View file details including upload timestamps and metadata
781
- - Files are sorted by most recent first
782
- - Use pagination to navigate through large file lists
783
-
784
- ### ⚠️ **Important Notes:**
785
- - File deletion is **permanent** and cannot be undone
786
- - Always verify your selection before deleting files
787
- - The system maps file titles to IDs internally for deletion
788
-
789
- ### πŸ“ž **Support:**
790
- For issues or questions, contact the development team.
791
  """
792
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
793
 
794
  if __name__ == "__main__":
795
- app.launch(
796
- server_name="0.0.0.0",
797
- server_port=7860,
798
- share=False,
799
- debug=True,
800
- show_error=True
801
- )
 
13
  # Load environment variables
14
  load_dotenv()
15
 
16
+ # Authentication configuration
17
+ AUTH_PASSWORD = "gst_magic@##56$$"
18
+
19
+ def authenticate(password):
20
+ """Simple authentication function"""
21
+ return password == AUTH_PASSWORD
22
+
23
  # Validate required environment variables
24
  required_env_vars = ["PINECONE_API_KEY"]
25
  missing_vars = [var for var in required_env_vars if not os.getenv(var)]
 
465
  """Show processing finished status"""
466
  return "βœ… **Processing completed successfully!**"
467
 
468
+ def create_main_interface():
469
+ """Create the main application interface"""
470
+ with gr.Blocks(
471
+ title="πŸ“„ Tax Document Ingestion System",
472
+ theme=gr.themes.Soft(),
473
+ css="""
474
+ .gradio-container {
475
+ max-width: 1400px !important;
476
+ margin: auto;
477
+ }
478
+ .upload-container {
479
+ border: 2px dashed #4CAF50;
480
+ border-radius: 10px;
481
+ padding: 20px;
482
+ text-align: center;
483
+ background-color: #f8f9fa;
484
+ }
485
+ .delete-container {
486
+ border: 2px dashed #f44336;
487
+ border-radius: 10px;
488
+ padding: 20px;
489
+ background-color: #ffebee;
490
+ }
491
+ .tab-nav {
492
+ margin-bottom: 20px;
493
+ }
 
 
 
494
  """
495
+ ) as app:
 
 
496
 
497
+ gr.Markdown(
498
+ """
499
+ # πŸ“„ Tax Document Ingestion System
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
500
 
501
+ Upload, manage, and delete documents in the Pinecone Assistant for GST Minutes processing.
 
 
 
 
 
502
 
503
+ ## πŸš€ Features:
504
+ - βœ… **Multiple file upload** - Select and upload multiple documents at once
505
+ - 🏷️ **Metadata tagging** - Add sections, keywords, and descriptions
506
+ - πŸ”„ **Batch processing** - All files processed with individual metadata
507
+ - πŸ—‘οΈ **File deletion** - Delete multiple files by selecting from dropdown
508
+ - πŸ“Š **File management** - View uploaded files with timestamps and metadata
509
+ - πŸ“‹ **Detailed reporting** - See success/failure status for each operation
510
 
511
+ ---
512
+ """
513
+ )
514
+
515
+ # Create tabs for different functionalities
516
+ with gr.Tabs() as tabs:
 
517
 
518
+ # Tab 1: Upload Documents
519
+ with gr.TabItem("πŸ“€ Upload Documents", id="upload_tab"):
520
+ with gr.Row():
521
+ with gr.Column(scale=1):
522
+ gr.Markdown("### πŸ“ **File Upload**")
523
+ files_input = gr.File(
524
+ label="Select Documents (Max 10 files)",
525
+ file_count="multiple",
526
+ file_types=[".pdf", ".doc", ".docx", ".txt"],
527
+ elem_classes=["upload-container"]
528
+ )
529
+
530
+ with gr.Column(scale=1):
531
+ gr.Markdown("### 🏷️ **Document Metadata (Individual for Each File)**")
532
+ gr.Markdown("*Upload files first, then metadata fields will appear for each document*")
533
+
534
+ # Dynamic metadata fields container
535
+ with gr.Column() as metadata_container:
536
+ # Create 30 text fields (enough for 10 files with 3 fields each)
537
+ metadata_fields = []
538
+ for i in range(30):
539
+ field = gr.Textbox(
540
+ label=f"Field {i}",
541
+ placeholder="",
542
+ visible=False,
543
+ lines=2
544
+ )
545
+ metadata_fields.append(field)
546
+
547
+ with gr.Row():
548
+ with gr.Column(scale=1):
549
+ upload_btn = gr.Button(
550
+ "πŸš€ Upload Documents to Pinecone Assistant",
551
+ variant="primary",
552
+ size="lg"
553
+ )
554
+
555
+ with gr.Column(scale=1):
556
+ clear_btn = gr.Button(
557
+ "πŸ—‘οΈ Clear Form",
558
+ variant="secondary",
559
+ size="lg"
560
+ )
561
+
562
+ # Processing status indicator
563
+ with gr.Row():
564
+ processing_status = gr.Markdown(
565
+ value="🟒 **Ready to process documents**",
566
+ visible=True
567
  )
568
+
569
+ gr.Markdown("---")
570
+
571
+ # Results section
572
+ with gr.Row():
573
+ with gr.Column():
574
+ status_output = gr.Markdown(
575
+ label="πŸ“Š Upload Status",
576
+ value="*Ready to upload documents...*"
577
+ )
578
+
579
+ with gr.Row():
580
+ with gr.Column():
581
+ results_output = gr.Markdown(
582
+ label="πŸ“‹ Detailed Results",
583
+ value="",
584
+ max_height=400 # Add height limit for scrolling
585
+ )
586
 
587
+ # Tab 2: Delete Documents
588
+ with gr.TabItem("πŸ—‘οΈ Delete Documents", id="delete_tab"):
589
+ gr.Markdown("### πŸ—‘οΈ **Delete Multiple Documents**")
590
+ gr.Markdown("Select multiple files from the dropdown to delete them from the Pinecone Assistant.")
591
+
592
+ with gr.Row():
593
+ with gr.Column(scale=2):
594
+ file_dropdown = gr.Dropdown(
595
+ label="πŸ“‹ Select Files to Delete (Multiple Selection)",
596
+ choices=[],
597
+ multiselect=True,
598
+ interactive=False,
599
+ elem_classes=["delete-container"]
600
+ )
601
+
602
+ with gr.Column(scale=1):
603
+ refresh_dropdown_btn = gr.Button(
604
+ "πŸ”„ Refresh File List",
605
+ variant="secondary",
606
+ size="lg"
607
+ )
608
+
609
+ with gr.Row():
610
+ with gr.Column(scale=1):
611
+ delete_btn = gr.Button(
612
+ "πŸ—‘οΈ Delete Selected Files",
613
+ variant="stop",
614
+ size="lg"
615
+ )
616
+
617
+ with gr.Column(scale=1):
618
+ clear_delete_btn = gr.Button(
619
+ "β†Ί Clear Selection",
620
+ variant="secondary",
621
+ size="lg"
622
+ )
623
+
624
+ gr.Markdown("---")
625
+
626
+ # Delete results section
627
+ with gr.Row():
628
+ with gr.Column():
629
+ delete_status_output = gr.Markdown(
630
+ label="πŸ“Š Deletion Status",
631
+ value="*Select files to delete...*"
632
+ )
633
+
634
+ with gr.Row():
635
+ with gr.Column():
636
+ delete_results_output = gr.Markdown(
637
+ label="πŸ—‘οΈ Deletion Results",
638
+ value="",
639
+ max_height=400
640
+ )
641
 
642
+ # Tab 3: View Uploaded Files
643
+ with gr.TabItem("πŸ“‹ View Uploaded Files", id="view_tab"):
644
+ gr.Markdown("### πŸ“‹ **Uploaded Files Management**")
645
+ gr.Markdown("View all files currently uploaded to the Pinecone Assistant with their metadata and timestamps.")
646
+
647
+ with gr.Row():
648
+ refresh_btn = gr.Button(
649
+ "πŸ”„ Fetch Files",
650
+ variant="primary",
 
 
 
 
 
651
  size="lg"
652
  )
653
+
654
+ # File list status
655
+ with gr.Row():
656
+ file_list_status = gr.Markdown(
657
+ value="🟑 **Click 'Fetch Files' to load uploaded files**",
658
+ visible=True
 
659
  )
660
+
661
+ gr.Markdown("---")
662
+
663
+ # Pagination controls
664
+ with gr.Row():
665
+ prev_btn = gr.Button(
666
+ "⬅️ Previous 100",
667
  variant="secondary",
668
+ visible=False
669
  )
670
+ pagination_info = gr.Markdown(
671
+ value="πŸ“„ Page 1 of 1 | Total: 0 files",
672
+ elem_classes=["pagination-info"]
 
 
 
 
 
 
673
  )
674
+ next_btn = gr.Button(
675
+ "Next 100 ➑️",
676
+ variant="secondary",
677
+ visible=False
 
 
 
678
  )
679
+
680
+ # File list results
681
+ with gr.Row():
682
+ with gr.Column(scale=1):
683
+ file_summary = gr.Markdown(
684
+ label="πŸ“Š Files Summary",
685
+ value="*Click refresh to load file summary...*"
686
+ )
687
+
688
+ with gr.Row():
689
+ with gr.Column():
690
+ file_details = gr.Markdown(
691
+ label="πŸ“‹ File Details",
692
+ value="*Click refresh to load file details...*",
693
+ max_height=600 # Add height limit for scrolling
694
+ )
695
+
696
+ # Event handlers for Upload tab
697
+
698
+ # Update metadata fields when files are uploaded
699
+ files_input.change(
700
+ fn=update_metadata_fields,
701
+ inputs=[files_input],
702
+ outputs=metadata_fields
703
+ )
704
 
705
+ # Show processing status when upload starts
706
+ upload_btn.click(
707
+ fn=start_processing,
708
+ outputs=[processing_status]
709
+ ).then(
710
+ fn=process_files_with_progress,
711
+ inputs=[files_input] + metadata_fields,
712
+ outputs=[status_output, results_output, processing_status]
713
+ )
714
+
715
+ clear_btn.click(
716
+ fn=clear_form,
717
+ outputs=[files_input] + metadata_fields + [status_output, results_output, processing_status]
718
+ )
719
+
720
+ # Event handlers for Delete tab
721
+
722
+ # Refresh dropdown with current files
723
+ refresh_dropdown_btn.click(
724
+ fn=refresh_delete_dropdown,
725
+ outputs=[file_dropdown]
726
+ )
727
+
728
+ # Delete selected files
729
+ delete_btn.click(
730
+ fn=delete_selected_files,
731
+ inputs=[file_dropdown],
732
+ outputs=[delete_status_output, delete_results_output]
733
+ )
734
+
735
+ # Clear delete form
736
+ clear_delete_btn.click(
737
+ fn=clear_delete_form,
738
+ outputs=[file_dropdown, delete_status_output, delete_results_output]
739
+ )
740
+
741
+ # Event handlers for View Files tab
742
+
743
+ # Fetch files - load page 1
744
+ refresh_btn.click(
745
+ fn=refresh_file_list,
746
+ outputs=[file_list_status]
747
+ ).then(
748
+ fn=list_uploaded_files_paginated,
749
+ inputs=[],
750
+ outputs=[file_summary, file_details, pagination_info, prev_btn, next_btn]
751
+ )
752
+
753
+ # Next page button
754
+ next_btn.click(
755
+ fn=load_next_page,
756
+ inputs=[pagination_info],
757
+ outputs=[file_summary, file_details, pagination_info, prev_btn, next_btn]
758
+ )
759
+
760
+ # Previous page button
761
+ prev_btn.click(
762
+ fn=load_prev_page,
763
+ inputs=[pagination_info],
764
+ outputs=[file_summary, file_details, pagination_info, prev_btn, next_btn]
765
+ )
766
+
767
+ # Footer
768
+ gr.Markdown(
769
+ """
770
+ ---
771
 
772
+ ### πŸ’‘ **Usage Tips:**
 
 
 
 
 
773
 
774
+ **Upload Documents:**
775
+ - Select up to 10 PDF, DOC, DOCX, or TXT files at once
776
+ - Upload files first, then fill individual metadata for each document
777
+ - Each file gets its own sections, keywords, and description
778
+ - Check the results section for upload status
 
779
 
780
+ **Delete Documents:**
781
+ - Click 'Refresh File List' to load current files in dropdown
782
+ - Select multiple files using the dropdown (supports multi-select)
783
+ - Click 'Delete Selected Files' to remove them permanently
784
+ - View deletion results for success/failure status
785
 
786
+ **View Uploaded Files:**
787
+ - Click 'Fetch Files' to see all uploaded files
788
+ - View file details including upload timestamps and metadata
789
+ - Files are sorted by most recent first
790
+ - Use pagination to navigate through large file lists
 
 
 
 
 
 
 
 
 
 
 
791
 
792
+ ### ⚠️ **Important Notes:**
793
+ - File deletion is **permanent** and cannot be undone
794
+ - Always verify your selection before deleting files
795
+ - The system maps file titles to IDs internally for deletion
 
 
 
796
 
797
+ ### πŸ“ž **Support:**
798
+ For issues or questions, contact the development team.
799
+ """
800
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
801
 
802
+ return app
803
+
804
+ def create_login_interface():
805
+ """Create the login interface"""
806
+ with gr.Blocks(
807
+ title="πŸ” Authentication Required",
808
+ theme=gr.themes.Soft(),
809
+ css="""
810
+ .gradio-container {
811
+ max-width: 500px !important;
812
+ margin: auto;
813
+ padding-top: 100px;
814
+ }
815
+ .login-container {
816
+ border: 2px solid #2196F3;
817
+ border-radius: 15px;
818
+ padding: 30px;
819
+ text-align: center;
820
+ background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
821
+ box-shadow: 0 10px 20px rgba(0,0,0,0.1);
822
+ }
823
+ .password-input {
824
+ margin: 20px 0;
825
+ }
826
+ .login-button {
827
+ margin-top: 15px;
828
+ }
829
+ .error-message {
830
+ color: #f44336;
831
+ font-weight: bold;
832
+ margin-top: 10px;
833
+ }
834
  """
835
+ ) as login_app:
836
+
837
+ with gr.Column(elem_classes=["login-container"]):
838
+ gr.Markdown(
839
+ """
840
+ # πŸ” **Tax Document System**
841
+ ## **Authentication Required**
842
+
843
+ Please enter the password to access the application.
844
+
845
+ ---
846
+ """
847
+ )
848
+
849
+ password_input = gr.Textbox(
850
+ label="πŸ”‘ Password",
851
+ type="password",
852
+ placeholder="Enter password to access the system",
853
+ elem_classes=["password-input"]
854
+ )
855
+
856
+ login_btn = gr.Button(
857
+ "πŸš€ Login",
858
+ variant="primary",
859
+ size="lg",
860
+ elem_classes=["login-button"]
861
+ )
862
+
863
+ error_message = gr.Markdown(
864
+ value="",
865
+ visible=False,
866
+ elem_classes=["error-message"]
867
+ )
868
+
869
+ gr.Markdown(
870
+ """
871
+ ---
872
+
873
+ ### πŸ›‘οΈ **Security Notice:**
874
+ - This system contains sensitive tax documentation
875
+ - Authorized access only
876
+ - All activities are logged
877
+
878
+ ### πŸ“ž **Need Access?**
879
+ Contact your system administrator for credentials.
880
+ """
881
+ )
882
+
883
+ return login_app, password_input, login_btn, error_message
884
+ def main():
885
+ """Main application with authentication β€” single Gradio Blocks app.
886
+
887
+ This builds both the login UI and the main application UI inside one
888
+ `gr.Blocks` so we only call `.launch()` once. The main UI is hidden
889
+ until authentication succeeds. This avoids launching two separate
890
+ Gradio servers which was causing the server to close unexpectedly.
891
+ """
892
+
893
+ # Reuse same theme/CSS as main app for consistency
894
+ app_css = """
895
+ .gradio-container {
896
+ max-width: 1400px !important;
897
+ margin: auto;
898
+ }
899
+ .upload-container {
900
+ border: 2px dashed #4CAF50;
901
+ border-radius: 10px;
902
+ padding: 20px;
903
+ text-align: center;
904
+ background-color: #f8f9fa;
905
+ }
906
+ .delete-container {
907
+ border: 2px dashed #f44336;
908
+ border-radius: 10px;
909
+ padding: 20px;
910
+ background-color: #ffebee;
911
+ }
912
+ .login-container {
913
+ border: 2px solid #2196F3;
914
+ border-radius: 15px;
915
+ padding: 30px;
916
+ text-align: center;
917
+ background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
918
+ box-shadow: 0 10px 20px rgba(0,0,0,0.1);
919
+ }
920
+ """
921
+
922
+ with gr.Blocks(title="Tax Document Ingestion System", theme=gr.themes.Soft(), css=app_css) as app:
923
+
924
+ # --- LOGIN CONTAINER (visible initially) ---
925
+ with gr.Column(elem_classes=["login-container"]) as login_container:
926
+ gr.Markdown("""
927
+ # Tax Document System
928
+ Authentication required
929
+ """)
930
+
931
+ password_input = gr.Textbox(
932
+ label="Password",
933
+ type="password",
934
+ placeholder="Enter password"
935
+ )
936
+
937
+ login_btn = gr.Button("Login", variant="primary", size="lg")
938
+
939
+ error_message = gr.Markdown(value="", visible=False)
940
+
941
+ # --- MAIN APP CONTAINER (hidden until auth) ---
942
+ with gr.Column(visible=False) as main_container:
943
+ # Insert main UI contents (slimmed text, no emojis)
944
+ gr.Markdown(
945
+ """
946
+ # Tax Document Ingestion System
947
+
948
+ Upload, manage, and delete documents in the Pinecone Assistant.
949
+ """
950
+ )
951
+
952
+ with gr.Tabs() as tabs:
953
+ # Upload Tab
954
+ with gr.TabItem("Upload Documents", id="upload_tab"):
955
+ with gr.Row():
956
+ with gr.Column(scale=1):
957
+ gr.Markdown("### File Upload")
958
+ files_input = gr.File(
959
+ label="Select Documents (Max 10 files)",
960
+ file_count="multiple",
961
+ file_types=[".pdf", ".doc", ".docx", ".txt"],
962
+ elem_classes=["upload-container"]
963
+ )
964
+ with gr.Column(scale=1):
965
+ gr.Markdown("### Document Metadata")
966
+
967
+ with gr.Column() as metadata_container:
968
+ metadata_fields = []
969
+ for i in range(30):
970
+ field = gr.Textbox(label=f"Field {i}", placeholder="", visible=False, lines=2)
971
+ metadata_fields.append(field)
972
+
973
+ with gr.Row():
974
+ with gr.Column(scale=1):
975
+ upload_btn = gr.Button("Upload Documents to Pinecone Assistant", variant="primary")
976
+ with gr.Column(scale=1):
977
+ clear_btn = gr.Button("Clear Form", variant="secondary")
978
+
979
+ processing_status = gr.Markdown(value="Ready to process documents", visible=True)
980
+
981
+ status_output = gr.Markdown(label="Upload Status", value="Ready to upload documents...")
982
+ results_output = gr.Markdown(label="Detailed Results", value="", max_height=400)
983
+
984
+ # Delete Tab
985
+ with gr.TabItem("Delete Documents", id="delete_tab"):
986
+ gr.Markdown("### Delete Documents")
987
+ with gr.Row():
988
+ with gr.Column(scale=2):
989
+ file_dropdown = gr.Dropdown(label="Select Files to Delete", choices=[], multiselect=True, interactive=False, elem_classes=["delete-container"])
990
+ with gr.Column(scale=1):
991
+ refresh_dropdown_btn = gr.Button("Refresh File List", variant="secondary")
992
+
993
+ with gr.Row():
994
+ with gr.Column(scale=1):
995
+ delete_btn = gr.Button("Delete Selected Files", variant="stop")
996
+ with gr.Column(scale=1):
997
+ clear_delete_btn = gr.Button("Clear Selection", variant="secondary")
998
+
999
+ delete_status_output = gr.Markdown(label="Deletion Status", value="Select files to delete...")
1000
+ delete_results_output = gr.Markdown(label="Deletion Results", value="", max_height=400)
1001
+
1002
+ # View Tab
1003
+ with gr.TabItem("View Uploaded Files", id="view_tab"):
1004
+ gr.Markdown("### Uploaded Files Management")
1005
+ with gr.Row():
1006
+ refresh_btn = gr.Button("Fetch Files", variant="primary")
1007
+
1008
+ file_list_status = gr.Markdown(value="Click 'Fetch Files' to load uploaded files", visible=True)
1009
+
1010
+ with gr.Row():
1011
+ prev_btn = gr.Button("Previous 100", variant="secondary", visible=False)
1012
+ pagination_info = gr.Markdown(value="Page 1 of 1 | Total: 0 files")
1013
+ next_btn = gr.Button("Next 100", variant="secondary", visible=False)
1014
+
1015
+ file_summary = gr.Markdown(label="Files Summary", value="Click refresh to load file summary...")
1016
+ file_details = gr.Markdown(label="File Details", value="Click refresh to load file details...", max_height=600)
1017
+
1018
+ # --- EVENT HANDLERS ---
1019
+ # Login handlers: show main_container on success, show error on failure
1020
+ def handle_login(password):
1021
+ if authenticate(password):
1022
+ return gr.update(visible=False), gr.update(value="", visible=False), gr.update(visible=True)
1023
+ else:
1024
+ return gr.update(visible=True), gr.update(value="Invalid password. Please try again.", visible=True), gr.update(visible=False)
1025
+
1026
+ login_btn.click(fn=handle_login, inputs=[password_input], outputs=[login_container, error_message, main_container])
1027
+ password_input.submit(fn=handle_login, inputs=[password_input], outputs=[login_container, error_message, main_container])
1028
+
1029
+ # Wiring existing handlers from earlier in the file
1030
+ files_input.change(fn=update_metadata_fields, inputs=[files_input], outputs=metadata_fields)
1031
+
1032
+ upload_btn.click(fn=start_processing, outputs=[processing_status]).then(
1033
+ fn=process_files_with_progress,
1034
+ inputs=[files_input] + metadata_fields,
1035
+ outputs=[status_output, results_output, processing_status]
1036
+ )
1037
+
1038
+ clear_btn.click(fn=clear_form, outputs=[files_input] + metadata_fields + [status_output, results_output, processing_status])
1039
+
1040
+ refresh_dropdown_btn.click(fn=refresh_delete_dropdown, outputs=[file_dropdown])
1041
+ delete_btn.click(fn=delete_selected_files, inputs=[file_dropdown], outputs=[delete_status_output, delete_results_output])
1042
+ clear_delete_btn.click(fn=clear_delete_form, outputs=[file_dropdown, delete_status_output, delete_results_output])
1043
+
1044
+ refresh_btn.click(fn=refresh_file_list, outputs=[file_list_status]).then(
1045
+ fn=list_uploaded_files_paginated,
1046
+ inputs=[],
1047
+ outputs=[file_summary, file_details, pagination_info, prev_btn, next_btn]
1048
+ )
1049
+
1050
+ next_btn.click(fn=load_next_page, inputs=[pagination_info], outputs=[file_summary, file_details, pagination_info, prev_btn, next_btn])
1051
+ prev_btn.click(fn=load_prev_page, inputs=[pagination_info], outputs=[file_summary, file_details, pagination_info, prev_btn, next_btn])
1052
+
1053
+ # Launch single app
1054
+ app.launch(server_name="0.0.0.0", server_port=7860, share=False, debug=True, show_error=True)
1055
 
1056
  if __name__ == "__main__":
1057
+ main()