atz21 commited on
Commit
6fb7138
ยท
verified ยท
1 Parent(s): 610d28c

Update app.py

Browse files

mass grading v1.2

Files changed (1) hide show
  1. app.py +149 -230
app.py CHANGED
@@ -680,274 +680,193 @@ with gr.Blocks(title="๐ŸŽ“ AI Mass Grading System", theme=gr.themes.Soft()) as d
680
  gr.Markdown("# ๐ŸŽ“ AI Mass Grading System")
681
  gr.Markdown("Upload multiple sets of Question Papers, Markschemes, and Answer Sheets for batch processing.")
682
 
683
- # Initialize with one triplet
684
- initial_triplet = {
685
- "qp_file": None,
686
- "ms_file": None,
687
- "ans_file": None,
688
- "imprint": False
689
- }
690
- triplets_state = gr.State([initial_triplet])
691
-
692
- # Initial triplet row (always visible)
693
  with gr.Row():
694
- qp_file_1 = gr.File(label="๐Ÿ“„ Upload Question Paper (PDF)", file_types=[".pdf"])
695
- ms_file_1 = gr.File(label="๐Ÿ“‹ Upload Markscheme (PDF)", file_types=[".pdf"])
696
- ans_file_1 = gr.File(label="๐Ÿ“ Upload Student Answer Sheet (PDF)", file_types=[".pdf"])
697
-
698
- imprint_check_1 = gr.Checkbox(label="โœ Imprint Marks on Student Answer Sheet", value=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
699
 
700
- # Dynamic container for additional triplets
701
- additional_triplets = gr.Column()
702
 
703
- # Buttons row
704
  with gr.Row():
705
- add_triplet_btn = gr.Button("โž• Add Another Set", variant="secondary")
706
- start_grading_btn = gr.Button("๐Ÿš€ Run Pipeline", variant="primary")
707
 
708
- # Status table
 
709
  status_table = gr.Dataframe(
710
- headers=["Set", "QP File", "MS File", "Answer Sheets", "Status"],
711
  datatype=["number", "str", "str", "str", "str"],
712
- label="๐Ÿ“Š Grading Status",
713
  visible=False
714
  )
715
 
716
- # Results section
717
  results_section = gr.Column(visible=False)
718
  with results_section:
719
  gr.Markdown("## ๐Ÿ“ฅ Download Results")
720
- results_files = gr.Column()
721
-
722
- def update_first_triplet_qp(file_obj, current_triplets):
723
- """Update QP file for first triplet."""
724
- current_triplets[0]["qp_file"] = file_obj.name if file_obj else None
725
- return current_triplets
726
-
727
- def update_first_triplet_ms(file_obj, current_triplets):
728
- """Update MS file for first triplet."""
729
- current_triplets[0]["ms_file"] = file_obj.name if file_obj else None
730
- return current_triplets
731
-
732
- def update_first_triplet_ans(file_obj, current_triplets):
733
- """Update AS file for first triplet."""
734
- current_triplets[0]["ans_file"] = file_obj.name if file_obj else None
735
- return current_triplets
736
 
737
- def update_first_triplet_imprint(imprint_val, current_triplets):
738
- """Update imprint setting for first triplet."""
739
- current_triplets[0]["imprint"] = imprint_val
740
- return current_triplets
741
-
742
- def add_triplet(current_triplets):
743
- """Add a new triplet to the list."""
744
- new_triplet = {
745
- "qp_file": None,
746
- "ms_file": None,
747
- "ans_file": None,
748
- "imprint": False
749
- }
750
- current_triplets.append(new_triplet)
751
- return current_triplets
752
-
753
- def remove_triplet(triplet_idx, current_triplets):
754
- """Remove a triplet from the list."""
755
- if triplet_idx < len(current_triplets) and len(current_triplets) > 1:
756
- current_triplets.pop(triplet_idx)
757
- return current_triplets
 
 
 
 
 
 
 
 
 
 
 
758
 
759
- def update_status_table(triplets):
760
- """Update the status table with current triplets."""
761
- if len(triplets) <= 1:
762
- return gr.update(visible=False, value=[])
 
 
 
 
 
 
 
 
 
 
 
 
 
763
 
 
 
764
  table_data = []
765
- for i, triplet in enumerate(triplets):
766
- qp_name = os.path.basename(triplet["qp_file"]) if triplet["qp_file"] else "Not uploaded"
767
- ms_name = os.path.basename(triplet["ms_file"]) if triplet["ms_file"] else "Not uploaded"
768
- ans_name = os.path.basename(triplet["ans_file"]) if triplet["ans_file"] else "Not uploaded"
 
769
 
770
  # Determine status
771
- if triplet["qp_file"] and triplet["ms_file"] and triplet["ans_file"]:
772
- status = "๐Ÿ“‹ Ready"
 
773
  else:
774
- status = "โณ Pending uploads"
775
 
776
  table_data.append([i + 1, qp_name, ms_name, ans_name, status])
777
 
778
- return gr.update(visible=True, value=table_data)
779
-
780
- def start_mass_grading(triplets):
781
- """Start processing all triplets."""
782
- if not triplets:
783
- return gr.update(), gr.update(visible=False)
784
 
785
- # Filter only complete triplets
786
- complete_triplets = [t for t in triplets if t["qp_file"] and t["ms_file"] and t["ans_file"]]
 
 
 
 
 
 
787
 
788
- if not complete_triplets:
789
- return gr.update(value=[["No complete triplets to process"]]), gr.update(visible=False)
 
 
 
 
790
 
791
- # Process triplets and update table progressively
792
- results = []
793
  table_data = []
794
-
795
- for i, triplet in enumerate(complete_triplets):
796
- # Update status to processing
797
- table_row = [
798
  i + 1,
799
  os.path.basename(triplet["qp_file"]),
800
  os.path.basename(triplet["ms_file"]),
801
  os.path.basename(triplet["ans_file"]),
802
  "๐Ÿ”„ Processing..."
803
- ]
804
- table_data.append(table_row)
805
-
806
- # Process the triplet
807
- result = process_single_triplet(triplet, i)
808
- results.append(result)
809
-
810
- # Update status
811
- table_data[i][4] = result["status"]
812
 
813
- return gr.update(value=table_data), gr.update(visible=True)
814
-
815
- # Event handlers for first triplet
816
- qp_file_1.change(
817
- fn=update_first_triplet_qp,
818
- inputs=[qp_file_1, triplets_state],
819
- outputs=[triplets_state]
820
- ).then(
821
- fn=update_status_table,
822
- inputs=[triplets_state],
823
- outputs=[status_table]
824
- )
825
-
826
- ms_file_1.change(
827
- fn=update_first_triplet_ms,
828
- inputs=[ms_file_1, triplets_state],
829
- outputs=[triplets_state]
830
- ).then(
831
- fn=update_status_table,
832
- inputs=[triplets_state],
833
- outputs=[status_table]
834
- )
835
-
836
- ans_file_1.change(
837
- fn=update_first_triplet_ans,
838
- inputs=[ans_file_1, triplets_state],
839
- outputs=[triplets_state]
840
- ).then(
841
- fn=update_status_table,
842
- inputs=[triplets_state],
843
- outputs=[status_table]
844
- )
845
-
846
- imprint_check_1.change(
847
- fn=update_first_triplet_imprint,
848
- inputs=[imprint_check_1, triplets_state],
849
- outputs=[triplets_state]
850
- )
851
-
852
- # Dynamic UI management for additional triplets
853
- @gr.render(inputs=[triplets_state])
854
- def render_additional_triplets(triplets):
855
- if len(triplets) <= 1:
856
- return
857
 
858
- for i in range(1, len(triplets)): # Start from index 1 (skip first triplet)
859
- with gr.Row():
860
- qp_file = gr.File(label=f"๐Ÿ“„ QP Set {i + 1}", file_types=[".pdf"])
861
- ms_file = gr.File(label=f"๐Ÿ“‹ MS Set {i + 1}", file_types=[".pdf"])
862
- ans_file = gr.File(label=f"๐Ÿ“ AS Set {i + 1}", file_types=[".pdf"])
863
-
864
- with gr.Row():
865
- imprint_check = gr.Checkbox(label=f"โœ Imprint Set {i + 1}", value=False)
866
- remove_btn = gr.Button("๐Ÿ—‘๏ธ Remove", variant="stop", size="sm")
867
-
868
- # File update handlers
869
- def create_file_handler(idx, file_type):
870
- def handler(file_obj, current_triplets):
871
- if idx < len(current_triplets):
872
- current_triplets[idx][file_type] = file_obj.name if file_obj else None
873
- return current_triplets
874
- return handler
875
-
876
- def create_imprint_handler(idx):
877
- def handler(imprint_val, current_triplets):
878
- if idx < len(current_triplets):
879
- current_triplets[idx]["imprint"] = imprint_val
880
- return current_triplets
881
- return handler
882
-
883
- def create_remove_handler(idx):
884
- def handler(current_triplets):
885
- return remove_triplet(idx, current_triplets)
886
- return handler
887
-
888
- # Set up event handlers
889
- qp_file.change(
890
- fn=create_file_handler(i, "qp_file"),
891
- inputs=[qp_file, triplets_state],
892
- outputs=[triplets_state]
893
- ).then(
894
- fn=update_status_table,
895
- inputs=[triplets_state],
896
- outputs=[status_table]
897
- )
898
-
899
- ms_file.change(
900
- fn=create_file_handler(i, "ms_file"),
901
- inputs=[ms_file, triplets_state],
902
- outputs=[triplets_state]
903
- ).then(
904
- fn=update_status_table,
905
- inputs=[triplets_state],
906
- outputs=[status_table]
907
- )
908
-
909
- ans_file.change(
910
- fn=create_file_handler(i, "ans_file"),
911
- inputs=[ans_file, triplets_state],
912
- outputs=[triplets_state]
913
- ).then(
914
- fn=update_status_table,
915
- inputs=[triplets_state],
916
- outputs=[status_table]
917
- )
918
-
919
- imprint_check.change(
920
- fn=create_imprint_handler(i),
921
- inputs=[imprint_check, triplets_state],
922
- outputs=[triplets_state]
923
- )
924
 
925
- remove_btn.click(
926
- fn=create_remove_handler(i),
927
- inputs=[triplets_state],
928
- outputs=[triplets_state]
929
- ).then(
930
- fn=update_status_table,
931
- inputs=[triplets_state],
932
- outputs=[status_table]
933
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
934
 
935
- # Add triplet button handler
936
- add_triplet_btn.click(
937
- fn=add_triplet,
938
- inputs=[triplets_state],
939
- outputs=[triplets_state]
940
- ).then(
941
- fn=update_status_table,
942
- inputs=[triplets_state],
943
- outputs=[status_table]
944
- )
945
 
946
- # Start grading button handler
947
  start_grading_btn.click(
948
- fn=start_mass_grading,
949
- inputs=[triplets_state],
950
- outputs=[status_table, results_section]
951
  )
952
 
953
  if __name__ == "__main__":
 
680
  gr.Markdown("# ๐ŸŽ“ AI Mass Grading System")
681
  gr.Markdown("Upload multiple sets of Question Papers, Markschemes, and Answer Sheets for batch processing.")
682
 
 
 
 
 
 
 
 
 
 
 
683
  with gr.Row():
684
+ with gr.Column():
685
+ qp_files = gr.File(
686
+ label="๐Ÿ“„ Upload Question Papers (PDF)",
687
+ file_count="multiple",
688
+ file_types=[".pdf"]
689
+ )
690
+ with gr.Column():
691
+ ms_files = gr.File(
692
+ label="๐Ÿ“‹ Upload Markschemes (PDF)",
693
+ file_count="multiple",
694
+ file_types=[".pdf"]
695
+ )
696
+ with gr.Column():
697
+ ans_files = gr.File(
698
+ label="๐Ÿ“ Upload Answer Sheets (PDF)",
699
+ file_count="multiple",
700
+ file_types=[".pdf"]
701
+ )
702
 
703
+ imprint_all = gr.Checkbox(label="โœ Imprint Marks on All Answer Sheets", value=False)
 
704
 
 
705
  with gr.Row():
706
+ start_grading_btn = gr.Button("๐Ÿš€ Start Mass Grading", variant="primary", size="lg")
 
707
 
708
+ # Status and results
709
+ status_info = gr.Markdown("", visible=False)
710
  status_table = gr.Dataframe(
711
+ headers=["Set", "QP File", "MS File", "Answer Sheet", "Status"],
712
  datatype=["number", "str", "str", "str", "str"],
713
+ label="๐Ÿ“Š Grading Progress",
714
  visible=False
715
  )
716
 
 
717
  results_section = gr.Column(visible=False)
718
  with results_section:
719
  gr.Markdown("## ๐Ÿ“ฅ Download Results")
720
+ results_container = gr.Column()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
721
 
722
+ def create_triplets_from_files(qp_list, ms_list, ans_list, imprint_setting):
723
+ """Create triplets from uploaded file lists."""
724
+ if not qp_list or not ms_list or not ans_list:
725
+ return []
726
+
727
+ # Convert single files to lists
728
+ if not isinstance(qp_list, list):
729
+ qp_list = [qp_list] if qp_list else []
730
+ if not isinstance(ms_list, list):
731
+ ms_list = [ms_list] if ms_list else []
732
+ if not isinstance(ans_list, list):
733
+ ans_list = [ans_list] if ans_list else []
734
+
735
+ # Create triplets by matching files by index
736
+ triplets = []
737
+ max_files = max(len(qp_list), len(ms_list), len(ans_list))
738
+
739
+ for i in range(max_files):
740
+ qp_file = qp_list[i].name if i < len(qp_list) else None
741
+ ms_file = ms_list[i].name if i < len(ms_list) else None
742
+ ans_file = ans_list[i].name if i < len(ans_list) else None
743
+
744
+ # Only create triplet if all three files are present
745
+ if qp_file and ms_file and ans_file:
746
+ triplets.append({
747
+ "qp_file": qp_file,
748
+ "ms_file": ms_file,
749
+ "ans_file": ans_file,
750
+ "imprint": imprint_setting
751
+ })
752
+
753
+ return triplets
754
 
755
+ def update_status_display(qp_list, ms_list, ans_list):
756
+ """Update the status display showing file matching."""
757
+ if not qp_list and not ms_list and not ans_list:
758
+ return gr.update(visible=False), gr.update(visible=False, value=[])
759
+
760
+ # Convert single files to lists
761
+ if not isinstance(qp_list, list):
762
+ qp_list = [qp_list] if qp_list else []
763
+ if not isinstance(ms_list, list):
764
+ ms_list = [ms_list] if ms_list else []
765
+ if not isinstance(ans_list, list):
766
+ ans_list = [ans_list] if ans_list else []
767
+
768
+ max_files = max(len(qp_list), len(ms_list), len(ans_list))
769
+
770
+ if max_files == 0:
771
+ return gr.update(visible=False), gr.update(visible=False, value=[])
772
 
773
+ # Create status info
774
+ complete_sets = 0
775
  table_data = []
776
+
777
+ for i in range(max_files):
778
+ qp_name = os.path.basename(qp_list[i].name) if i < len(qp_list) else "โŒ Missing"
779
+ ms_name = os.path.basename(ms_list[i].name) if i < len(ms_list) else "โŒ Missing"
780
+ ans_name = os.path.basename(ans_list[i].name) if i < len(ans_list) else "โŒ Missing"
781
 
782
  # Determine status
783
+ if i < len(qp_list) and i < len(ms_list) and i < len(ans_list):
784
+ status = "โœ… Ready"
785
+ complete_sets += 1
786
  else:
787
+ status = "โณ Incomplete"
788
 
789
  table_data.append([i + 1, qp_name, ms_name, ans_name, status])
790
 
791
+ status_text = f"**๐Ÿ“Š File Summary:** {complete_sets} complete set(s) ready for grading out of {max_files} total."
 
 
 
 
 
792
 
793
+ return (
794
+ gr.update(visible=True, value=status_text),
795
+ gr.update(visible=True, value=table_data)
796
+ )
797
+
798
+ def process_mass_grading(qp_list, ms_list, ans_list, imprint_setting):
799
+ """Process all complete triplets."""
800
+ triplets = create_triplets_from_files(qp_list, ms_list, ans_list, imprint_setting)
801
 
802
+ if not triplets:
803
+ return (
804
+ gr.update(value="โŒ No complete sets found. Please ensure each set has QP, MS, and AS files."),
805
+ gr.update(visible=False),
806
+ gr.update(visible=False)
807
+ )
808
 
809
+ # Update status to show processing
 
810
  table_data = []
811
+ for i, triplet in enumerate(triplets):
812
+ table_data.append([
 
 
813
  i + 1,
814
  os.path.basename(triplet["qp_file"]),
815
  os.path.basename(triplet["ms_file"]),
816
  os.path.basename(triplet["ans_file"]),
817
  "๐Ÿ”„ Processing..."
818
+ ])
 
 
 
 
 
 
 
 
819
 
820
+ # Process each triplet
821
+ results = []
822
+ result_components = []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
823
 
824
+ for i, triplet in enumerate(triplets):
825
+ print(f"\n๐Ÿ”„ Processing Set {i + 1}/{len(triplets)}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
826
 
827
+ try:
828
+ result = process_single_triplet(triplet, i)
829
+ results.append(result)
830
+
831
+ # Update table status
832
+ table_data[i][4] = result["status"]
833
+
834
+ # Create download components
835
+ if result["grading_pdf"]:
836
+ result_components.append(
837
+ gr.File(value=result["grading_pdf"], label=f"๐Ÿ“„ Set {i+1} - Grading PDF", visible=True)
838
+ )
839
+ if result["imprinted_pdf"]:
840
+ result_components.append(
841
+ gr.File(value=result["imprinted_pdf"], label=f"โœ๏ธ Set {i+1} - Imprinted PDF", visible=True)
842
+ )
843
+
844
+ except Exception as e:
845
+ print(f"โŒ Error processing set {i + 1}: {e}")
846
+ table_data[i][4] = f"โŒ Error: {str(e)[:30]}..."
847
+
848
+ # Final status
849
+ successful = len([r for r in results if r.get("status") == "โœ… Complete"])
850
+ status_text = f"**๐Ÿ Processing Complete:** {successful}/{len(triplets)} sets processed successfully."
851
+
852
+ return (
853
+ gr.update(value=status_text),
854
+ gr.update(value=table_data),
855
+ gr.update(visible=True)
856
+ )
857
 
858
+ # Event handlers
859
+ for file_input in [qp_files, ms_files, ans_files]:
860
+ file_input.change(
861
+ fn=update_status_display,
862
+ inputs=[qp_files, ms_files, ans_files],
863
+ outputs=[status_info, status_table]
864
+ )
 
 
 
865
 
 
866
  start_grading_btn.click(
867
+ fn=process_mass_grading,
868
+ inputs=[qp_files, ms_files, ans_files, imprint_all],
869
+ outputs=[status_info, status_table, results_section]
870
  )
871
 
872
  if __name__ == "__main__":