Commit
·
d20f881
1
Parent(s):
2b4b7c5
fix the htr
Browse files- HTR/app.py +4 -1
- HTR/hcr.py +22 -1
- main.py +76 -40
HTR/app.py
CHANGED
@@ -70,7 +70,10 @@ def extract_text_from_image(img_path):
|
|
70 |
imgs = convert_image(img)
|
71 |
if not imgs:
|
72 |
logger.error("No text regions detected in image")
|
73 |
-
|
|
|
|
|
|
|
74 |
|
75 |
logger.info(f"Found {len(imgs)} text regions")
|
76 |
|
|
|
70 |
imgs = convert_image(img)
|
71 |
if not imgs:
|
72 |
logger.error("No text regions detected in image")
|
73 |
+
# Try processing the whole image as one region
|
74 |
+
temp_path = os.path.join(tempfile.gettempdir(), 'whole_image.png')
|
75 |
+
cv2.imwrite(temp_path, img)
|
76 |
+
imgs = [temp_path]
|
77 |
|
78 |
logger.info(f"Found {len(imgs)} text regions")
|
79 |
|
HTR/hcr.py
CHANGED
@@ -26,15 +26,36 @@ def text(image_cv):
|
|
26 |
# Initialize model if not already done
|
27 |
initialize_model()
|
28 |
|
|
|
|
|
|
|
29 |
t = ""
|
30 |
for i in image_cv:
|
31 |
try:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
32 |
# Convert BGR to RGB
|
33 |
img_rgb = cv2.cvtColor(i, cv2.COLOR_BGR2RGB)
|
|
|
|
|
34 |
image = Image.fromarray(img_rgb)
|
35 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
36 |
# Process image
|
37 |
pixel_values = processor(image, return_tensors="pt").pixel_values
|
|
|
38 |
if torch.cuda.is_available():
|
39 |
pixel_values = pixel_values.to('cuda')
|
40 |
|
@@ -43,7 +64,7 @@ def text(image_cv):
|
|
43 |
t = t + generated_text.replace(" ", "") + " "
|
44 |
|
45 |
except Exception as e:
|
46 |
-
print(f"Error processing image: {str(e)}")
|
47 |
continue
|
48 |
|
49 |
return t.strip()
|
|
|
26 |
# Initialize model if not already done
|
27 |
initialize_model()
|
28 |
|
29 |
+
if not isinstance(image_cv, list):
|
30 |
+
image_cv = [image_cv]
|
31 |
+
|
32 |
t = ""
|
33 |
for i in image_cv:
|
34 |
try:
|
35 |
+
# Ensure image is in correct format
|
36 |
+
if isinstance(i, str):
|
37 |
+
# If i is a path, read the image
|
38 |
+
i = cv2.imread(i)
|
39 |
+
if i is None:
|
40 |
+
print(f"Failed to read image")
|
41 |
+
continue
|
42 |
+
|
43 |
# Convert BGR to RGB
|
44 |
img_rgb = cv2.cvtColor(i, cv2.COLOR_BGR2RGB)
|
45 |
+
|
46 |
+
# Convert numpy array to PIL Image
|
47 |
image = Image.fromarray(img_rgb)
|
48 |
|
49 |
+
# Resize if image is too small
|
50 |
+
min_size = 224 # minimum size required by the model
|
51 |
+
if image.size[0] < min_size or image.size[1] < min_size:
|
52 |
+
ratio = max(min_size/image.size[0], min_size/image.size[1])
|
53 |
+
new_size = tuple([int(dim * ratio) for dim in image.size])
|
54 |
+
image = image.resize(new_size, Image.Refilter.LANCZOS)
|
55 |
+
|
56 |
# Process image
|
57 |
pixel_values = processor(image, return_tensors="pt").pixel_values
|
58 |
+
|
59 |
if torch.cuda.is_available():
|
60 |
pixel_values = pixel_values.to('cuda')
|
61 |
|
|
|
64 |
t = t + generated_text.replace(" ", "") + " "
|
65 |
|
66 |
except Exception as e:
|
67 |
+
print(f"Error processing individual image: {str(e)}")
|
68 |
continue
|
69 |
|
70 |
return t.strip()
|
main.py
CHANGED
@@ -264,6 +264,7 @@ def compute_marks():
|
|
264 |
|
265 |
# Dictionary to store results by student folder
|
266 |
results = {}
|
|
|
267 |
|
268 |
# Process each file
|
269 |
for file in files:
|
@@ -290,48 +291,72 @@ def compute_marks():
|
|
290 |
filepath = os.path.join(student_dir, filename)
|
291 |
file.save(filepath)
|
292 |
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
if not extracted_text:
|
297 |
-
log_print(f"No text extracted from {file.filename}", "WARNING")
|
298 |
-
continue
|
299 |
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
-
tfidf_score = tfidf_answer_score(extracted_text, correct_answer)
|
310 |
-
ft_score = fasttext_similarity(extracted_text, correct_answer)
|
311 |
-
llm_marks = llm_score(extracted_text, correct_answer)
|
312 |
|
313 |
-
#
|
314 |
-
|
315 |
-
|
316 |
-
word_score * 0.2 +
|
317 |
-
tfidf_score * 0.2 +
|
318 |
-
ft_score * 0.2 +
|
319 |
-
llm_marks * 0.1
|
320 |
-
)
|
321 |
|
322 |
-
#
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
332 |
|
333 |
except Exception as e:
|
334 |
log_print(f"Error processing file {file.filename}: {str(e)}", "ERROR")
|
|
|
|
|
|
|
|
|
335 |
continue
|
336 |
|
337 |
# Clean up
|
@@ -345,7 +370,10 @@ def compute_marks():
|
|
345 |
return jsonify({"error": "No results computed"}), 400
|
346 |
|
347 |
log_print(f"Computed marks for {len(results)} students")
|
348 |
-
return jsonify({
|
|
|
|
|
|
|
349 |
|
350 |
except Exception as e:
|
351 |
log_print(f"Error computing marks: {str(e)}", "ERROR")
|
@@ -360,10 +388,18 @@ def check_logs():
|
|
360 |
except Exception as e:
|
361 |
return jsonify({"error": str(e)})
|
362 |
|
363 |
-
# Add file type validation
|
364 |
def is_valid_image_file(filename):
|
365 |
-
|
366 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
367 |
|
368 |
def allowed_file(filename, allowed_extensions):
|
369 |
return '.' in filename and \
|
|
|
264 |
|
265 |
# Dictionary to store results by student folder
|
266 |
results = {}
|
267 |
+
failed_files = [] # Track failed files
|
268 |
|
269 |
# Process each file
|
270 |
for file in files:
|
|
|
291 |
filepath = os.path.join(student_dir, filename)
|
292 |
file.save(filepath)
|
293 |
|
294 |
+
try:
|
295 |
+
# Extract text from image with better error handling
|
296 |
+
extracted_text = extract_text_from_image(filepath)
|
|
|
|
|
|
|
297 |
|
298 |
+
if not extracted_text or len(extracted_text.strip()) == 0:
|
299 |
+
log_print(f"No valid text extracted from {file.filename}", "WARNING")
|
300 |
+
failed_files.append({
|
301 |
+
"file": file.filename,
|
302 |
+
"error": "No text could be extracted"
|
303 |
+
})
|
304 |
+
continue
|
305 |
+
|
306 |
+
log_print(f"Successfully extracted text from {file.filename}: {extracted_text[:100]}...")
|
|
|
|
|
|
|
307 |
|
308 |
+
# Find which answer this matches best
|
309 |
+
best_score = 0
|
310 |
+
best_answer_index = 0
|
|
|
|
|
|
|
|
|
|
|
311 |
|
312 |
+
# Compare with each correct answer
|
313 |
+
for i, correct_answer in enumerate(correct_answers):
|
314 |
+
try:
|
315 |
+
# Calculate different similarity scores with error handling
|
316 |
+
semantic_score = question_vector_sentence(extracted_text, correct_answer)
|
317 |
+
word_score = question_vector_word(extracted_text, correct_answer)
|
318 |
+
tfidf_score = tfidf_answer_score(extracted_text, correct_answer)
|
319 |
+
ft_score = fasttext_similarity(extracted_text, correct_answer)
|
320 |
+
llm_marks = llm_score(extracted_text, correct_answer)
|
321 |
+
|
322 |
+
# Combine scores with weights
|
323 |
+
combined_score = (
|
324 |
+
semantic_score * 0.3 +
|
325 |
+
word_score * 0.2 +
|
326 |
+
tfidf_score * 0.2 +
|
327 |
+
ft_score * 0.2 +
|
328 |
+
llm_marks * 0.1
|
329 |
+
)
|
330 |
+
|
331 |
+
# Update if this is the best matching answer
|
332 |
+
if combined_score > best_score:
|
333 |
+
best_score = combined_score
|
334 |
+
best_answer_index = i
|
335 |
+
|
336 |
+
except Exception as score_error:
|
337 |
+
log_print(f"Error calculating scores for {file.filename}: {str(score_error)}", "ERROR")
|
338 |
+
continue
|
339 |
+
|
340 |
+
# Scale the score to 0-5 range
|
341 |
+
marks = new_value(best_score, 0, 1, 0, 5)
|
342 |
+
|
343 |
+
# Update the student's score for this answer
|
344 |
+
results[student_folder][best_answer_index] = round(marks, 2)
|
345 |
+
|
346 |
+
except Exception as extract_error:
|
347 |
+
log_print(f"Error extracting text from {file.filename}: {str(extract_error)}", "ERROR")
|
348 |
+
failed_files.append({
|
349 |
+
"file": file.filename,
|
350 |
+
"error": str(extract_error)
|
351 |
+
})
|
352 |
+
continue
|
353 |
|
354 |
except Exception as e:
|
355 |
log_print(f"Error processing file {file.filename}: {str(e)}", "ERROR")
|
356 |
+
failed_files.append({
|
357 |
+
"file": file.filename,
|
358 |
+
"error": str(e)
|
359 |
+
})
|
360 |
continue
|
361 |
|
362 |
# Clean up
|
|
|
370 |
return jsonify({"error": "No results computed"}), 400
|
371 |
|
372 |
log_print(f"Computed marks for {len(results)} students")
|
373 |
+
return jsonify({
|
374 |
+
"results": results,
|
375 |
+
"failed_files": failed_files # Include failed files in response
|
376 |
+
}), 200
|
377 |
|
378 |
except Exception as e:
|
379 |
log_print(f"Error computing marks: {str(e)}", "ERROR")
|
|
|
388 |
except Exception as e:
|
389 |
return jsonify({"error": str(e)})
|
390 |
|
|
|
391 |
def is_valid_image_file(filename):
|
392 |
+
"""Validate image file extensions and basic format"""
|
393 |
+
try:
|
394 |
+
# Check file extension
|
395 |
+
valid_extensions = {'.jpg', '.jpeg', '.png'}
|
396 |
+
ext = os.path.splitext(filename)[1].lower()
|
397 |
+
if ext not in valid_extensions:
|
398 |
+
return False
|
399 |
+
|
400 |
+
return True
|
401 |
+
except Exception:
|
402 |
+
return False
|
403 |
|
404 |
def allowed_file(filename, allowed_extensions):
|
405 |
return '.' in filename and \
|