Commit
·
8efbae1
1
Parent(s):
750ccee
update_
Browse files- main.py +40 -29
- templates/index.html +65 -27
main.py
CHANGED
@@ -280,26 +280,41 @@ def compute_marks():
|
|
280 |
processed_answers.append(ans)
|
281 |
answers = processed_answers
|
282 |
|
283 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
284 |
data = {}
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
303 |
|
304 |
# Initialize vectors for answers
|
305 |
sen_vec_answers = []
|
@@ -315,10 +330,10 @@ def compute_marks():
|
|
315 |
|
316 |
# Calculate marks
|
317 |
s_marks = {}
|
318 |
-
for student_folder in data:
|
319 |
s_marks[student_folder] = []
|
320 |
count = 0
|
321 |
-
for image_path in
|
322 |
try:
|
323 |
s_answer = extract_text_from_image(image_path)
|
324 |
log_print(f"\nProcessing {student_folder}/{os.path.basename(image_path)}:")
|
@@ -344,18 +359,14 @@ def compute_marks():
|
|
344 |
log_print(f"Error processing {image_path}: {str(e)}", "ERROR")
|
345 |
s_marks[student_folder].append(0)
|
346 |
|
|
|
|
|
|
|
|
|
347 |
log_print("\nFinal Results:")
|
348 |
for student, marks_list in s_marks.items():
|
349 |
log_print(f"{student}: {marks_list}")
|
350 |
|
351 |
-
# Add cleanup at the end
|
352 |
-
try:
|
353 |
-
import shutil
|
354 |
-
shutil.rmtree(ans_image_dir)
|
355 |
-
os.makedirs(ans_image_dir, exist_ok=True)
|
356 |
-
except Exception as e:
|
357 |
-
log_print(f"Warning: Could not clean up ans_image directory: {e}", "WARNING")
|
358 |
-
|
359 |
return jsonify({"message": s_marks}), 200
|
360 |
|
361 |
except Exception as e:
|
|
|
280 |
processed_answers.append(ans)
|
281 |
answers = processed_answers
|
282 |
|
283 |
+
# Get files from the request
|
284 |
+
files = request.files.getlist('files[]')
|
285 |
+
if not files:
|
286 |
+
log_print("No files were uploaded", "ERROR")
|
287 |
+
return jsonify({"error": "No files were uploaded"}), 400
|
288 |
+
|
289 |
+
# Create student folders and save files
|
290 |
data = {}
|
291 |
+
for file in files:
|
292 |
+
if file and is_valid_image_file(file.filename):
|
293 |
+
# Extract student folder from the path
|
294 |
+
path_parts = file.filename.split('/')
|
295 |
+
if len(path_parts) >= 2:
|
296 |
+
student_folder = path_parts[-2] # Get the parent folder name
|
297 |
+
filename = path_parts[-1] # Get the actual filename
|
298 |
+
|
299 |
+
# Create student directory if it doesn't exist
|
300 |
+
student_dir = os.path.join(ans_image_dir, student_folder)
|
301 |
+
os.makedirs(student_dir, exist_ok=True)
|
302 |
+
|
303 |
+
# Save the file
|
304 |
+
filepath = os.path.join(student_dir, filename)
|
305 |
+
file.save(filepath)
|
306 |
+
|
307 |
+
# Add to data structure
|
308 |
+
if student_folder not in data:
|
309 |
+
data[student_folder] = []
|
310 |
+
data[student_folder].append(filepath.replace("\\", "/"))
|
311 |
+
log_print(f"Saved file: {filepath}")
|
312 |
+
|
313 |
+
if not data:
|
314 |
+
log_print("No valid image files were found in the upload", "ERROR")
|
315 |
+
return jsonify({"error": "No valid image files were found"}), 400
|
316 |
+
|
317 |
+
log_print(f"Processed files structure: {data}")
|
318 |
|
319 |
# Initialize vectors for answers
|
320 |
sen_vec_answers = []
|
|
|
330 |
|
331 |
# Calculate marks
|
332 |
s_marks = {}
|
333 |
+
for student_folder, file_paths in data.items():
|
334 |
s_marks[student_folder] = []
|
335 |
count = 0
|
336 |
+
for image_path in file_paths:
|
337 |
try:
|
338 |
s_answer = extract_text_from_image(image_path)
|
339 |
log_print(f"\nProcessing {student_folder}/{os.path.basename(image_path)}:")
|
|
|
359 |
log_print(f"Error processing {image_path}: {str(e)}", "ERROR")
|
360 |
s_marks[student_folder].append(0)
|
361 |
|
362 |
+
if not s_marks:
|
363 |
+
log_print("No marks were computed", "ERROR")
|
364 |
+
return jsonify({"error": "No marks were computed. Please check your input files and answers."}), 400
|
365 |
+
|
366 |
log_print("\nFinal Results:")
|
367 |
for student, marks_list in s_marks.items():
|
368 |
log_print(f"{student}: {marks_list}")
|
369 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
370 |
return jsonify({"message": s_marks}), 200
|
371 |
|
372 |
except Exception as e:
|
templates/index.html
CHANGED
@@ -499,6 +499,39 @@
|
|
499 |
margin-top: 0;
|
500 |
color: #4361ee;
|
501 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
502 |
</style>
|
503 |
</head>
|
504 |
<body>
|
@@ -570,6 +603,13 @@
|
|
570 |
</div>
|
571 |
</div>
|
572 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
573 |
<script>
|
574 |
document.addEventListener('DOMContentLoaded', function() {
|
575 |
const fileTypeSelect = document.getElementById('file-type');
|
@@ -613,8 +653,17 @@
|
|
613 |
handleFileTypeChange();
|
614 |
});
|
615 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
616 |
async function computeAnswers() {
|
617 |
try {
|
|
|
618 |
const fileType = document.getElementById('file-type').value;
|
619 |
const queryfile = document.getElementById('query-file').files[0];
|
620 |
const anscsvFile = document.getElementById('csv-file').files[0];
|
@@ -622,6 +671,7 @@
|
|
622 |
|
623 |
if (!queryfile) {
|
624 |
alert("Please upload a query file first!");
|
|
|
625 |
return;
|
626 |
}
|
627 |
|
@@ -632,20 +682,22 @@
|
|
632 |
if (fileType === 'csv') {
|
633 |
if (!anscsvFile) {
|
634 |
alert("Please upload a CSV file for answers!");
|
|
|
635 |
return;
|
636 |
}
|
637 |
formData.append('ans_csv_file', anscsvFile);
|
638 |
} else if (fileType === 'pdf') {
|
639 |
if (!pdfFiles || pdfFiles.length < 2) {
|
640 |
alert("Please upload at least 2 PDF files!");
|
|
|
641 |
return;
|
642 |
}
|
643 |
-
|
|
|
|
|
644 |
}
|
645 |
|
646 |
-
// Show loading state
|
647 |
const computeBtn = document.getElementById('compute-btn');
|
648 |
-
computeBtn.textContent = 'Processing...';
|
649 |
computeBtn.disabled = true;
|
650 |
|
651 |
const response = await fetch('/compute_answers', {
|
@@ -668,17 +720,12 @@
|
|
668 |
throw new Error('No answers received from server');
|
669 |
}
|
670 |
|
671 |
-
// Reset button state
|
672 |
-
computeBtn.textContent = 'Compute Answers';
|
673 |
-
computeBtn.disabled = false;
|
674 |
-
|
675 |
} catch (error) {
|
676 |
console.error('Error:', error);
|
677 |
alert('Error: ' + error.message);
|
678 |
-
|
679 |
-
|
680 |
const computeBtn = document.getElementById('compute-btn');
|
681 |
-
computeBtn.textContent = 'Compute Answers';
|
682 |
computeBtn.disabled = false;
|
683 |
}
|
684 |
}
|
@@ -896,37 +943,34 @@
|
|
896 |
|
897 |
async function computeMarks() {
|
898 |
try {
|
|
|
899 |
const answerBoxes = document.querySelectorAll('.answer-box');
|
900 |
if (answerBoxes.length === 0) {
|
901 |
alert("Please generate answers first!");
|
|
|
902 |
return;
|
903 |
}
|
904 |
|
905 |
-
// Validate that answers are not empty
|
906 |
const answerValues = Array.from(answerBoxes).map(box => box.value.trim());
|
907 |
if (answerValues.some(answer => !answer)) {
|
908 |
alert("Please ensure all answer boxes are filled!");
|
|
|
909 |
return;
|
910 |
}
|
911 |
|
912 |
if (selectedFiles.size === 0) {
|
913 |
alert("Please upload student answer files!");
|
|
|
914 |
return;
|
915 |
}
|
916 |
|
917 |
-
// Show loading state
|
918 |
const computeBtn = document.getElementById('compute-marks-btn');
|
919 |
-
computeBtn.textContent = 'Processing...';
|
920 |
computeBtn.disabled = true;
|
921 |
|
922 |
-
// Get answers from textboxes
|
923 |
-
const answers = Array.from(answerBoxes).map(box => box.value);
|
924 |
-
console.log("Sending answers:", answers);
|
925 |
-
|
926 |
const formData = new FormData();
|
927 |
-
formData.append('answers', JSON.stringify(
|
928 |
|
929 |
-
// Add files with their paths
|
930 |
let validFiles = 0;
|
931 |
selectedFiles.forEach((fileInfo, path) => {
|
932 |
if (fileInfo.file.type.startsWith('image/')) {
|
@@ -950,8 +994,6 @@
|
|
950 |
}
|
951 |
|
952 |
const result = await response.json();
|
953 |
-
console.log("Received result:", result);
|
954 |
-
|
955 |
if (result.error) {
|
956 |
throw new Error(result.error);
|
957 |
}
|
@@ -962,16 +1004,12 @@
|
|
962 |
|
963 |
displayMarks(result.message);
|
964 |
|
965 |
-
// Reset button
|
966 |
-
computeBtn.textContent = 'Compute Marks';
|
967 |
-
computeBtn.disabled = false;
|
968 |
-
|
969 |
} catch (error) {
|
970 |
console.error('Error:', error);
|
971 |
alert('Error computing marks: ' + error.message);
|
972 |
-
|
|
|
973 |
const computeBtn = document.getElementById('compute-marks-btn');
|
974 |
-
computeBtn.textContent = 'Compute Marks';
|
975 |
computeBtn.disabled = false;
|
976 |
}
|
977 |
}
|
|
|
499 |
margin-top: 0;
|
500 |
color: #4361ee;
|
501 |
}
|
502 |
+
|
503 |
+
.loading-overlay {
|
504 |
+
position: fixed;
|
505 |
+
top: 0;
|
506 |
+
left: 0;
|
507 |
+
width: 100%;
|
508 |
+
height: 100%;
|
509 |
+
background: rgba(0, 0, 0, 0.7);
|
510 |
+
display: none;
|
511 |
+
justify-content: center;
|
512 |
+
align-items: center;
|
513 |
+
z-index: 1000;
|
514 |
+
}
|
515 |
+
|
516 |
+
.loading-spinner {
|
517 |
+
width: 50px;
|
518 |
+
height: 50px;
|
519 |
+
border: 5px solid #f3f3f3;
|
520 |
+
border-top: 5px solid #4361ee;
|
521 |
+
border-radius: 50%;
|
522 |
+
animation: spin 1s linear infinite;
|
523 |
+
}
|
524 |
+
|
525 |
+
.loading-text {
|
526 |
+
color: white;
|
527 |
+
margin-top: 20px;
|
528 |
+
font-size: 18px;
|
529 |
+
}
|
530 |
+
|
531 |
+
@keyframes spin {
|
532 |
+
0% { transform: rotate(0deg); }
|
533 |
+
100% { transform: rotate(360deg); }
|
534 |
+
}
|
535 |
</style>
|
536 |
</head>
|
537 |
<body>
|
|
|
603 |
</div>
|
604 |
</div>
|
605 |
|
606 |
+
<div class="loading-overlay" id="loading-overlay">
|
607 |
+
<div style="text-align: center;">
|
608 |
+
<div class="loading-spinner"></div>
|
609 |
+
<div class="loading-text">Processing... This may take a few minutes.</div>
|
610 |
+
</div>
|
611 |
+
</div>
|
612 |
+
|
613 |
<script>
|
614 |
document.addEventListener('DOMContentLoaded', function() {
|
615 |
const fileTypeSelect = document.getElementById('file-type');
|
|
|
653 |
handleFileTypeChange();
|
654 |
});
|
655 |
|
656 |
+
function showLoading() {
|
657 |
+
document.getElementById('loading-overlay').style.display = 'flex';
|
658 |
+
}
|
659 |
+
|
660 |
+
function hideLoading() {
|
661 |
+
document.getElementById('loading-overlay').style.display = 'none';
|
662 |
+
}
|
663 |
+
|
664 |
async function computeAnswers() {
|
665 |
try {
|
666 |
+
showLoading();
|
667 |
const fileType = document.getElementById('file-type').value;
|
668 |
const queryfile = document.getElementById('query-file').files[0];
|
669 |
const anscsvFile = document.getElementById('csv-file').files[0];
|
|
|
671 |
|
672 |
if (!queryfile) {
|
673 |
alert("Please upload a query file first!");
|
674 |
+
hideLoading();
|
675 |
return;
|
676 |
}
|
677 |
|
|
|
682 |
if (fileType === 'csv') {
|
683 |
if (!anscsvFile) {
|
684 |
alert("Please upload a CSV file for answers!");
|
685 |
+
hideLoading();
|
686 |
return;
|
687 |
}
|
688 |
formData.append('ans_csv_file', anscsvFile);
|
689 |
} else if (fileType === 'pdf') {
|
690 |
if (!pdfFiles || pdfFiles.length < 2) {
|
691 |
alert("Please upload at least 2 PDF files!");
|
692 |
+
hideLoading();
|
693 |
return;
|
694 |
}
|
695 |
+
for (let file of pdfFiles) {
|
696 |
+
formData.append('pdf_files[]', file);
|
697 |
+
}
|
698 |
}
|
699 |
|
|
|
700 |
const computeBtn = document.getElementById('compute-btn');
|
|
|
701 |
computeBtn.disabled = true;
|
702 |
|
703 |
const response = await fetch('/compute_answers', {
|
|
|
720 |
throw new Error('No answers received from server');
|
721 |
}
|
722 |
|
|
|
|
|
|
|
|
|
723 |
} catch (error) {
|
724 |
console.error('Error:', error);
|
725 |
alert('Error: ' + error.message);
|
726 |
+
} finally {
|
727 |
+
hideLoading();
|
728 |
const computeBtn = document.getElementById('compute-btn');
|
|
|
729 |
computeBtn.disabled = false;
|
730 |
}
|
731 |
}
|
|
|
943 |
|
944 |
async function computeMarks() {
|
945 |
try {
|
946 |
+
showLoading();
|
947 |
const answerBoxes = document.querySelectorAll('.answer-box');
|
948 |
if (answerBoxes.length === 0) {
|
949 |
alert("Please generate answers first!");
|
950 |
+
hideLoading();
|
951 |
return;
|
952 |
}
|
953 |
|
|
|
954 |
const answerValues = Array.from(answerBoxes).map(box => box.value.trim());
|
955 |
if (answerValues.some(answer => !answer)) {
|
956 |
alert("Please ensure all answer boxes are filled!");
|
957 |
+
hideLoading();
|
958 |
return;
|
959 |
}
|
960 |
|
961 |
if (selectedFiles.size === 0) {
|
962 |
alert("Please upload student answer files!");
|
963 |
+
hideLoading();
|
964 |
return;
|
965 |
}
|
966 |
|
|
|
967 |
const computeBtn = document.getElementById('compute-marks-btn');
|
|
|
968 |
computeBtn.disabled = true;
|
969 |
|
|
|
|
|
|
|
|
|
970 |
const formData = new FormData();
|
971 |
+
formData.append('answers', JSON.stringify(answerValues));
|
972 |
|
973 |
+
// Add files with their paths
|
974 |
let validFiles = 0;
|
975 |
selectedFiles.forEach((fileInfo, path) => {
|
976 |
if (fileInfo.file.type.startsWith('image/')) {
|
|
|
994 |
}
|
995 |
|
996 |
const result = await response.json();
|
|
|
|
|
997 |
if (result.error) {
|
998 |
throw new Error(result.error);
|
999 |
}
|
|
|
1004 |
|
1005 |
displayMarks(result.message);
|
1006 |
|
|
|
|
|
|
|
|
|
1007 |
} catch (error) {
|
1008 |
console.error('Error:', error);
|
1009 |
alert('Error computing marks: ' + error.message);
|
1010 |
+
} finally {
|
1011 |
+
hideLoading();
|
1012 |
const computeBtn = document.getElementById('compute-marks-btn');
|
|
|
1013 |
computeBtn.disabled = false;
|
1014 |
}
|
1015 |
}
|