Skip to main content

Grade an exam

Request

Send a multipart/form-data request to POST /api/v1/grade with both parts required:

PartJava typeContent
imageMultipartFileThe answer-sheet image.
answersMultipartFileCSV answer key.

The answer-key CSV is parsed into AnswerKey objects. Its header and fields are:

questionNumber,correctAnswer
1,B
2,B

The controller does not define optional parts, authentication headers, content validation, upload limits, or a stable list of accepted image formats. The OpenCV reader is used for the uploaded file after it is copied to a temporary .jpg file.

Example

curl -s -X POST http://localhost:8080/api/v1/grade \
-F "image=@data/test_1.jpeg" \
-F "answers=@/tmp/answers.csv"

Response

On success, the body is a GradeResult with exactly these Java fields:

FieldTypeMeaning
studentNameStringOCR result from the name crop.
classNameStringOCR result from the class crop.
scoredoubleCorrect answers divided by total answer-key rows, multiplied by 10, rounded to two decimals.
correctCountintNumber of answer-key rows matching the extracted answer, case-insensitively.
totalQuestionsintNumber of parsed answer-key rows.
incorrectQuestionsList<Integer>Question numbers whose extracted answer did not match.
studentAnswersMap<Integer, String>Extracted answer string for questions 1 through 40.

For example, the JSON representation contains keys equivalent to:

{
"studentName": "...",
"className": "...",
"score": 10.0,
"correctCount": 40,
"totalQuestions": 40,
"incorrectQuestions": [],
"studentAnswers": {"1": "B", "2": "B"}
}

The number of graded questions is driven by the answer-key row count; the image extractor itself always creates entries for questions 1 through 40.