Commit
·
67a4609
1
Parent(s):
a3d1bae
adding some more thing for popup
Browse files- main.py +97 -5
- templates/index.html +49 -22
main.py
CHANGED
@@ -377,6 +377,7 @@ def compute_marks():
|
|
377 |
if not initialization_complete.is_set():
|
378 |
log_print("Initialization timeout", "ERROR")
|
379 |
return jsonify({
|
|
|
380 |
"error": "Server initialization",
|
381 |
"message": "Server is still initializing. Please try again in a moment."
|
382 |
}), 503
|
@@ -385,6 +386,7 @@ def compute_marks():
|
|
385 |
if not request.is_json and not request.form:
|
386 |
log_print("Invalid request format", "ERROR")
|
387 |
return jsonify({
|
|
|
388 |
"error": "Invalid request format",
|
389 |
"message": "Request must be either JSON or form data"
|
390 |
}), 400
|
@@ -394,6 +396,7 @@ def compute_marks():
|
|
394 |
if not correct_answers:
|
395 |
log_print("No correct answers provided", "ERROR")
|
396 |
return jsonify({
|
|
|
397 |
"error": "Missing data",
|
398 |
"message": "No correct answers provided"
|
399 |
}), 400
|
@@ -402,14 +405,28 @@ def compute_marks():
|
|
402 |
|
403 |
# Create TFIDF values for correct answers
|
404 |
try:
|
405 |
-
log_print("
|
|
|
|
|
|
|
|
|
406 |
max_tfidf = create_tfidf_values(correct_answers)
|
407 |
-
log_print("
|
|
|
|
|
|
|
|
|
408 |
except Exception as e:
|
409 |
-
|
|
|
|
|
|
|
|
|
|
|
410 |
return jsonify({
|
|
|
411 |
"error": "TFIDF error",
|
412 |
-
"message": f"Error creating TFIDF values: {
|
413 |
}), 400
|
414 |
|
415 |
# Get all uploaded files
|
@@ -417,6 +434,7 @@ def compute_marks():
|
|
417 |
if not files:
|
418 |
log_print("No files uploaded", "ERROR")
|
419 |
return jsonify({
|
|
|
420 |
"error": "Missing data",
|
421 |
"message": "No files uploaded"
|
422 |
}), 400
|
@@ -432,6 +450,7 @@ def compute_marks():
|
|
432 |
if total_size > max_size:
|
433 |
log_print(f"File size limit exceeded: {total_size / 1024 / 1024:.1f}MB", "ERROR")
|
434 |
return jsonify({
|
|
|
435 |
"error": "File size limit exceeded",
|
436 |
"message": f"Total file size must be less than 15MB (current size: {total_size / 1024 / 1024:.1f}MB)"
|
437 |
}), 413
|
@@ -443,6 +462,7 @@ def compute_marks():
|
|
443 |
if not is_valid:
|
444 |
log_print(f"Invalid folder structure: {message}", "ERROR")
|
445 |
return jsonify({
|
|
|
446 |
"error": "Invalid folder structure",
|
447 |
"message": message
|
448 |
}), 400
|
@@ -455,6 +475,7 @@ def compute_marks():
|
|
455 |
except Exception as e:
|
456 |
log_print(f"Error creating temp directory: {str(e)}", "ERROR")
|
457 |
return jsonify({
|
|
|
458 |
"error": "Server error",
|
459 |
"message": "Could not create temporary directory"
|
460 |
}), 500
|
@@ -478,6 +499,10 @@ def compute_marks():
|
|
478 |
continue
|
479 |
|
480 |
log_print(f"Processing file: {file.filename}")
|
|
|
|
|
|
|
|
|
481 |
|
482 |
# Get folder structure from file path
|
483 |
path_parts = file.filename.split('/')
|
@@ -518,9 +543,31 @@ def compute_marks():
|
|
518 |
log_print(f"Saved file to: {filepath}")
|
519 |
|
520 |
# Extract text
|
521 |
-
log_print(f"
|
|
|
|
|
|
|
|
|
522 |
extracted_text = extract_text_from_image(filepath)
|
523 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
524 |
# Clean up the file immediately after processing
|
525 |
try:
|
526 |
os.remove(filepath)
|
@@ -529,6 +576,10 @@ def compute_marks():
|
|
529 |
|
530 |
if not extracted_text:
|
531 |
log_print(f"No text extracted from: {filepath}", "WARNING")
|
|
|
|
|
|
|
|
|
532 |
failed_files.append({
|
533 |
"file": file.filename,
|
534 |
"error": "No text could be extracted from the image"
|
@@ -562,13 +613,35 @@ def compute_marks():
|
|
562 |
clean_correct_answer = correct_answer.encode('ascii', 'ignore').decode('ascii')
|
563 |
|
564 |
# Calculate similarity scores
|
|
|
|
|
|
|
|
|
|
|
|
|
565 |
log_print(f"Calculating scores for answer {i+1}...")
|
|
|
|
|
|
|
|
|
|
|
566 |
semantic_score = question_vector_sentence(extracted_text, clean_correct_answer)
|
567 |
word_score = question_vector_word(extracted_text, clean_correct_answer)
|
568 |
tfidf_score = tfidf_answer_score(extracted_text, clean_correct_answer, max_tfidf)
|
569 |
ft_score = fasttext_similarity(extracted_text, clean_correct_answer)
|
570 |
llm_marks = llm_score(extracted_text, clean_correct_answer)
|
571 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
572 |
combined_score = (
|
573 |
semantic_score * 0.3 +
|
574 |
word_score * 0.2 +
|
@@ -586,6 +659,10 @@ def compute_marks():
|
|
586 |
except Exception as score_error:
|
587 |
error_msg = str(score_error).encode('ascii', 'ignore').decode('ascii')
|
588 |
log_print(f"Error calculating scores for {filepath}: {error_msg}", "ERROR")
|
|
|
|
|
|
|
|
|
589 |
failed_files.append({
|
590 |
"file": file.filename,
|
591 |
"error": f"Error calculating scores: {error_msg}"
|
@@ -595,6 +672,10 @@ def compute_marks():
|
|
595 |
marks = new_value(best_score, 0, 1, 0, 5)
|
596 |
results[student_folder][filename] = round(marks, 2)
|
597 |
log_print(f"Assigned marks for {filename} in {student_folder}: {marks}")
|
|
|
|
|
|
|
|
|
598 |
|
599 |
# Update progress
|
600 |
processed_count += 1
|
@@ -610,6 +691,10 @@ def compute_marks():
|
|
610 |
except Exception as e:
|
611 |
error_msg = str(e).encode('ascii', 'ignore').decode('ascii')
|
612 |
log_print(f"Error processing file {file.filename}: {error_msg}", "ERROR")
|
|
|
|
|
|
|
|
|
613 |
failed_files.append({
|
614 |
"file": file.filename,
|
615 |
"error": error_msg
|
@@ -619,6 +704,10 @@ def compute_marks():
|
|
619 |
except Exception as e:
|
620 |
error_msg = str(e).encode('ascii', 'ignore').decode('ascii')
|
621 |
log_print(f"Error processing file {file.filename}: {error_msg}", "ERROR")
|
|
|
|
|
|
|
|
|
622 |
failed_files.append({
|
623 |
"file": file.filename,
|
624 |
"error": error_msg
|
@@ -636,6 +725,7 @@ def compute_marks():
|
|
636 |
if not results:
|
637 |
log_print("No results computed", "ERROR")
|
638 |
return jsonify({
|
|
|
639 |
"error": "Processing error",
|
640 |
"message": "No results computed"
|
641 |
}), 400
|
@@ -653,6 +743,7 @@ def compute_marks():
|
|
653 |
log_print(f"Final results: {clean_results}")
|
654 |
|
655 |
response_data = {
|
|
|
656 |
"results": clean_results,
|
657 |
"failed_files": [{
|
658 |
"file": f["file"].encode('ascii', 'ignore').decode('ascii'),
|
@@ -674,6 +765,7 @@ def compute_marks():
|
|
674 |
error_msg = str(e).encode('ascii', 'ignore').decode('ascii')
|
675 |
log_print(f"Error in compute_marks: {error_msg}", "ERROR")
|
676 |
return jsonify({
|
|
|
677 |
"error": "Server error",
|
678 |
"message": f"Error computing marks: {error_msg}"
|
679 |
}), 500
|
|
|
377 |
if not initialization_complete.is_set():
|
378 |
log_print("Initialization timeout", "ERROR")
|
379 |
return jsonify({
|
380 |
+
"status": "error",
|
381 |
"error": "Server initialization",
|
382 |
"message": "Server is still initializing. Please try again in a moment."
|
383 |
}), 503
|
|
|
386 |
if not request.is_json and not request.form:
|
387 |
log_print("Invalid request format", "ERROR")
|
388 |
return jsonify({
|
389 |
+
"status": "error",
|
390 |
"error": "Invalid request format",
|
391 |
"message": "Request must be either JSON or form data"
|
392 |
}), 400
|
|
|
396 |
if not correct_answers:
|
397 |
log_print("No correct answers provided", "ERROR")
|
398 |
return jsonify({
|
399 |
+
"status": "error",
|
400 |
"error": "Missing data",
|
401 |
"message": "No correct answers provided"
|
402 |
}), 400
|
|
|
405 |
|
406 |
# Create TFIDF values for correct answers
|
407 |
try:
|
408 |
+
log_print("Starting TFIDF value creation...")
|
409 |
+
notification_queue.put({
|
410 |
+
"type": "info",
|
411 |
+
"message": "Starting TFIDF value creation..."
|
412 |
+
})
|
413 |
max_tfidf = create_tfidf_values(correct_answers)
|
414 |
+
log_print("TFIDF values created successfully")
|
415 |
+
notification_queue.put({
|
416 |
+
"type": "success",
|
417 |
+
"message": "TFIDF values created successfully"
|
418 |
+
})
|
419 |
except Exception as e:
|
420 |
+
error_msg = str(e).encode('ascii', 'ignore').decode('ascii')
|
421 |
+
log_print(f"TFIDF error: {error_msg}", "ERROR")
|
422 |
+
notification_queue.put({
|
423 |
+
"type": "error",
|
424 |
+
"message": f"TFIDF error: {error_msg}"
|
425 |
+
})
|
426 |
return jsonify({
|
427 |
+
"status": "error",
|
428 |
"error": "TFIDF error",
|
429 |
+
"message": f"Error creating TFIDF values: {error_msg}"
|
430 |
}), 400
|
431 |
|
432 |
# Get all uploaded files
|
|
|
434 |
if not files:
|
435 |
log_print("No files uploaded", "ERROR")
|
436 |
return jsonify({
|
437 |
+
"status": "error",
|
438 |
"error": "Missing data",
|
439 |
"message": "No files uploaded"
|
440 |
}), 400
|
|
|
450 |
if total_size > max_size:
|
451 |
log_print(f"File size limit exceeded: {total_size / 1024 / 1024:.1f}MB", "ERROR")
|
452 |
return jsonify({
|
453 |
+
"status": "error",
|
454 |
"error": "File size limit exceeded",
|
455 |
"message": f"Total file size must be less than 15MB (current size: {total_size / 1024 / 1024:.1f}MB)"
|
456 |
}), 413
|
|
|
462 |
if not is_valid:
|
463 |
log_print(f"Invalid folder structure: {message}", "ERROR")
|
464 |
return jsonify({
|
465 |
+
"status": "error",
|
466 |
"error": "Invalid folder structure",
|
467 |
"message": message
|
468 |
}), 400
|
|
|
475 |
except Exception as e:
|
476 |
log_print(f"Error creating temp directory: {str(e)}", "ERROR")
|
477 |
return jsonify({
|
478 |
+
"status": "error",
|
479 |
"error": "Server error",
|
480 |
"message": "Could not create temporary directory"
|
481 |
}), 500
|
|
|
499 |
continue
|
500 |
|
501 |
log_print(f"Processing file: {file.filename}")
|
502 |
+
notification_queue.put({
|
503 |
+
"type": "info",
|
504 |
+
"message": f"Processing file: {file.filename}"
|
505 |
+
})
|
506 |
|
507 |
# Get folder structure from file path
|
508 |
path_parts = file.filename.split('/')
|
|
|
543 |
log_print(f"Saved file to: {filepath}")
|
544 |
|
545 |
# Extract text
|
546 |
+
log_print(f"Starting text extraction from: {filepath}")
|
547 |
+
notification_queue.put({
|
548 |
+
"type": "info",
|
549 |
+
"message": f"Starting text extraction from: {filename}"
|
550 |
+
})
|
551 |
extracted_text = extract_text_from_image(filepath)
|
552 |
|
553 |
+
if not extracted_text:
|
554 |
+
log_print(f"No text extracted from: {filepath}", "WARNING")
|
555 |
+
notification_queue.put({
|
556 |
+
"type": "warning",
|
557 |
+
"message": f"No text could be extracted from: {filename}"
|
558 |
+
})
|
559 |
+
failed_files.append({
|
560 |
+
"file": file.filename,
|
561 |
+
"error": "No text could be extracted from the image"
|
562 |
+
})
|
563 |
+
continue
|
564 |
+
|
565 |
+
log_print(f"Text extracted successfully from: {filename}")
|
566 |
+
notification_queue.put({
|
567 |
+
"type": "success",
|
568 |
+
"message": f"Text extracted successfully from: {filename}"
|
569 |
+
})
|
570 |
+
|
571 |
# Clean up the file immediately after processing
|
572 |
try:
|
573 |
os.remove(filepath)
|
|
|
576 |
|
577 |
if not extracted_text:
|
578 |
log_print(f"No text extracted from: {filepath}", "WARNING")
|
579 |
+
notification_queue.put({
|
580 |
+
"type": "warning",
|
581 |
+
"message": f"No text could be extracted from: {filename}"
|
582 |
+
})
|
583 |
failed_files.append({
|
584 |
"file": file.filename,
|
585 |
"error": "No text could be extracted from the image"
|
|
|
613 |
clean_correct_answer = correct_answer.encode('ascii', 'ignore').decode('ascii')
|
614 |
|
615 |
# Calculate similarity scores
|
616 |
+
log_print("Starting similarity score calculations...")
|
617 |
+
notification_queue.put({
|
618 |
+
"type": "info",
|
619 |
+
"message": "Starting similarity score calculations..."
|
620 |
+
})
|
621 |
+
|
622 |
log_print(f"Calculating scores for answer {i+1}...")
|
623 |
+
notification_queue.put({
|
624 |
+
"type": "info",
|
625 |
+
"message": f"Calculating scores for answer {i+1}..."
|
626 |
+
})
|
627 |
+
|
628 |
semantic_score = question_vector_sentence(extracted_text, clean_correct_answer)
|
629 |
word_score = question_vector_word(extracted_text, clean_correct_answer)
|
630 |
tfidf_score = tfidf_answer_score(extracted_text, clean_correct_answer, max_tfidf)
|
631 |
ft_score = fasttext_similarity(extracted_text, clean_correct_answer)
|
632 |
llm_marks = llm_score(extracted_text, clean_correct_answer)
|
633 |
|
634 |
+
# Send individual scores to frontend
|
635 |
+
notification_queue.put({
|
636 |
+
"type": "info",
|
637 |
+
"message": f"Scores for answer {i+1}:\n" +
|
638 |
+
f"Semantic: {semantic_score:.2f}\n" +
|
639 |
+
f"Word: {word_score:.2f}\n" +
|
640 |
+
f"TFIDF: {tfidf_score:.2f}\n" +
|
641 |
+
f"FastText: {ft_score:.2f}\n" +
|
642 |
+
f"LLM: {llm_marks:.2f}"
|
643 |
+
})
|
644 |
+
|
645 |
combined_score = (
|
646 |
semantic_score * 0.3 +
|
647 |
word_score * 0.2 +
|
|
|
659 |
except Exception as score_error:
|
660 |
error_msg = str(score_error).encode('ascii', 'ignore').decode('ascii')
|
661 |
log_print(f"Error calculating scores for {filepath}: {error_msg}", "ERROR")
|
662 |
+
notification_queue.put({
|
663 |
+
"type": "error",
|
664 |
+
"message": f"Error calculating scores for {filename}: {error_msg}"
|
665 |
+
})
|
666 |
failed_files.append({
|
667 |
"file": file.filename,
|
668 |
"error": f"Error calculating scores: {error_msg}"
|
|
|
672 |
marks = new_value(best_score, 0, 1, 0, 5)
|
673 |
results[student_folder][filename] = round(marks, 2)
|
674 |
log_print(f"Assigned marks for {filename} in {student_folder}: {marks}")
|
675 |
+
notification_queue.put({
|
676 |
+
"type": "success",
|
677 |
+
"message": f"Assigned marks for {filename}: {marks}"
|
678 |
+
})
|
679 |
|
680 |
# Update progress
|
681 |
processed_count += 1
|
|
|
691 |
except Exception as e:
|
692 |
error_msg = str(e).encode('ascii', 'ignore').decode('ascii')
|
693 |
log_print(f"Error processing file {file.filename}: {error_msg}", "ERROR")
|
694 |
+
notification_queue.put({
|
695 |
+
"type": "error",
|
696 |
+
"message": f"Error processing file {file.filename}: {error_msg}"
|
697 |
+
})
|
698 |
failed_files.append({
|
699 |
"file": file.filename,
|
700 |
"error": error_msg
|
|
|
704 |
except Exception as e:
|
705 |
error_msg = str(e).encode('ascii', 'ignore').decode('ascii')
|
706 |
log_print(f"Error processing file {file.filename}: {error_msg}", "ERROR")
|
707 |
+
notification_queue.put({
|
708 |
+
"type": "error",
|
709 |
+
"message": f"Error processing file {file.filename}: {error_msg}"
|
710 |
+
})
|
711 |
failed_files.append({
|
712 |
"file": file.filename,
|
713 |
"error": error_msg
|
|
|
725 |
if not results:
|
726 |
log_print("No results computed", "ERROR")
|
727 |
return jsonify({
|
728 |
+
"status": "error",
|
729 |
"error": "Processing error",
|
730 |
"message": "No results computed"
|
731 |
}), 400
|
|
|
743 |
log_print(f"Final results: {clean_results}")
|
744 |
|
745 |
response_data = {
|
746 |
+
"status": "success",
|
747 |
"results": clean_results,
|
748 |
"failed_files": [{
|
749 |
"file": f["file"].encode('ascii', 'ignore').decode('ascii'),
|
|
|
765 |
error_msg = str(e).encode('ascii', 'ignore').decode('ascii')
|
766 |
log_print(f"Error in compute_marks: {error_msg}", "ERROR")
|
767 |
return jsonify({
|
768 |
+
"status": "error",
|
769 |
"error": "Server error",
|
770 |
"message": f"Error computing marks: {error_msg}"
|
771 |
}), 500
|
templates/index.html
CHANGED
@@ -1312,7 +1312,11 @@
|
|
1312 |
const response = await fetch('/compute_marks', {
|
1313 |
method: 'POST',
|
1314 |
body: formData,
|
1315 |
-
keepalive: true
|
|
|
|
|
|
|
|
|
1316 |
});
|
1317 |
console.log(`Server response status: ${response.status}`);
|
1318 |
notificationSystem.info(`Server response status: ${response.status}`);
|
@@ -1334,34 +1338,57 @@
|
|
1334 |
return;
|
1335 |
}
|
1336 |
|
1337 |
-
|
1338 |
-
|
1339 |
-
|
1340 |
-
|
1341 |
-
|
1342 |
-
|
1343 |
-
const loadingText = document.querySelector('.loading-text');
|
1344 |
-
if (loadingText) {
|
1345 |
-
loadingText.innerHTML = `
|
1346 |
Processing ${data.total} files...<br>
|
1347 |
This may take several minutes depending on the number of files.<br>
|
1348 |
Please keep this window open.<br>
|
1349 |
<small>Progress: ${data.processed}/${data.total} files processed<br>
|
1350 |
Current file: ${data.current_file}</small>
|
1351 |
`;
|
|
|
|
|
|
|
1352 |
}
|
1353 |
-
|
1354 |
-
|
1355 |
-
|
1356 |
-
|
1357 |
-
|
1358 |
-
|
1359 |
-
|
1360 |
-
|
1361 |
-
|
1362 |
-
|
1363 |
-
|
1364 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1365 |
}
|
1366 |
} catch (e) {
|
1367 |
console.error('Error parsing notification data:', e);
|
|
|
1312 |
const response = await fetch('/compute_marks', {
|
1313 |
method: 'POST',
|
1314 |
body: formData,
|
1315 |
+
keepalive: true,
|
1316 |
+
headers: {
|
1317 |
+
'Accept': 'application/json',
|
1318 |
+
'X-Requested-With': 'XMLHttpRequest'
|
1319 |
+
}
|
1320 |
});
|
1321 |
console.log(`Server response status: ${response.status}`);
|
1322 |
notificationSystem.info(`Server response status: ${response.status}`);
|
|
|
1338 |
return;
|
1339 |
}
|
1340 |
|
1341 |
+
// Update loading text with more detailed information
|
1342 |
+
const loadingText = document.querySelector('.loading-text');
|
1343 |
+
if (loadingText) {
|
1344 |
+
let currentText = loadingText.innerHTML;
|
1345 |
+
if (data.type === 'progress') {
|
1346 |
+
currentText = `
|
|
|
|
|
|
|
1347 |
Processing ${data.total} files...<br>
|
1348 |
This may take several minutes depending on the number of files.<br>
|
1349 |
Please keep this window open.<br>
|
1350 |
<small>Progress: ${data.processed}/${data.total} files processed<br>
|
1351 |
Current file: ${data.current_file}</small>
|
1352 |
`;
|
1353 |
+
} else if (data.type === 'info' || data.type === 'success' || data.type === 'warning' || data.type === 'error') {
|
1354 |
+
// Add the new message to the existing text
|
1355 |
+
currentText += `<br><small>${data.message}</small>`;
|
1356 |
}
|
1357 |
+
loadingText.innerHTML = currentText;
|
1358 |
+
}
|
1359 |
+
|
1360 |
+
// Handle different notification types
|
1361 |
+
switch (data.type) {
|
1362 |
+
case 'extracted_text':
|
1363 |
+
console.log(`Extracted text from ${data.filename}`);
|
1364 |
+
notificationSystem.info(`Extracted text from ${data.filename}:\n${data.text}`, 8000);
|
1365 |
+
break;
|
1366 |
+
case 'progress':
|
1367 |
+
console.log(`Progress update: ${data.processed}/${data.total} files`);
|
1368 |
+
notificationSystem.info(`Progress: ${data.processed}/${data.total} files processed\nCurrent file: ${data.current_file}`, 5000);
|
1369 |
+
errorCount = 0;
|
1370 |
+
break;
|
1371 |
+
case 'info':
|
1372 |
+
console.log('Info:', data.message);
|
1373 |
+
notificationSystem.info(data.message, 5000);
|
1374 |
+
break;
|
1375 |
+
case 'success':
|
1376 |
+
console.log('Success:', data.message);
|
1377 |
+
notificationSystem.success(data.message, 5000);
|
1378 |
+
break;
|
1379 |
+
case 'warning':
|
1380 |
+
console.warn('Warning:', data.message);
|
1381 |
+
notificationSystem.warning(data.message, 6000);
|
1382 |
+
break;
|
1383 |
+
case 'error':
|
1384 |
+
console.error('Error:', data.message);
|
1385 |
+
notificationSystem.error(data.message, 8000);
|
1386 |
+
errorCount++;
|
1387 |
+
if (errorCount >= maxErrors) {
|
1388 |
+
eventSource.close();
|
1389 |
+
notificationSystem.error('Lost connection to server. Please refresh the page.');
|
1390 |
+
}
|
1391 |
+
break;
|
1392 |
}
|
1393 |
} catch (e) {
|
1394 |
console.error('Error parsing notification data:', e);
|