Grade an exam
POST /api/v1/grade is the only implemented HTTP endpoint. It consumes multipart/form-data with both of these required request parameters:
| Part | Type | Meaning |
|---|---|---|
image | file | The exam sheet image processed by OpenCV. |
answers | file | A header-based CSV answer key parsed with OpenCSV. |
The CSV header names are questionNumber and correctAnswer:
questionNumber,correctAnswer
1,B
2,C
3,A
The service compares detected answers to every CSV row, case-insensitively. score is (correctCount / number of CSV rows) * 10, rounded to two decimals. An empty answer key produces score 0.0.
Request example
curl -X POST http://localhost:8080/api/v1/grade \
-F "image=@data/test_1.jpeg" \
-F "answers=@answer_key.csv"
localhost:8080 is a local example, not a public deployment recommendation.
Successful response
On success the controller returns HTTP 200 and serializes GradeResult with these fields:
| Field | Java type | Meaning |
|---|---|---|
studentName | String | OCR output from the fixed name crop. |
className | String | OCR output from the fixed class crop. |
score | double | Score on a 0-10 scale, rounded to two decimals. |
correctCount | int | Number of CSV rows with matching detected answers. |
totalQuestions | int | Number of rows parsed from the submitted CSV, not necessarily 40. |
incorrectQuestions | List<Integer> | CSV question numbers that did not match. |
studentAnswers | Map<Integer, String> | Detected answers for questions 1 through 40. |
Example shape:
{
"studentName": "...",
"className": "...",
"score": 8.75,
"correctCount": 35,
"totalQuestions": 40,
"incorrectQuestions": [6, 17, 29, 40],
"studentAnswers": {"1": "B", "2": "C"}
}
This is documentation of the current Java model, not a versioned or stable OpenAPI schema. Do not assume input validation, file-type checks, upload-size limits, authentication, authorization, CORS behavior, or 4xx response contracts. See errors.