linguaielts-api / fronted /src /utils /scoring.js
AnhviNguyen
first commit
b1a388c
Raw
History Blame Contribute Delete
2.18 kB
import { isListeningQuiz } from '@/utils/mockQuiz.js'
function normalizeText(s) {
return String(s ?? '').trim().toLowerCase()
}
export function isCorrectAnswer({ question, userAnswer }) {
const q = question || {}
// Multi-answers (gap filling, multiple-choice-many)
if (Array.isArray(q.correct_answers) && q.correct_answers.length) {
if (Array.isArray(userAnswer)) {
const ua = userAnswer.map(normalizeText).sort().join('|')
const ca = q.correct_answers.map(normalizeText).sort().join('|')
return ua === ca
}
const ua = normalizeText(userAnswer)
return q.correct_answers.some((a) => normalizeText(a) === ua)
}
if (q.correct_answer !== undefined && q.correct_answer !== null && q.correct_answer !== '') {
return normalizeText(userAnswer) === normalizeText(q.correct_answer)
}
return false
}
export function scoreQuiz({ quiz, flat, answers }) {
const detailed = []
let correct = 0
for (const item of flat) {
const q = item.question
const userAnswer = answers?.[q?.id]
const ok = isCorrectAnswer({ question: q, userAnswer })
if (ok) correct += 1
detailed.push({
order: q?.order,
questionId: q?.id,
text: q?.text,
userAnswer,
correct_answer: q?.correct_answer,
correct_answers: q?.correct_answers,
isCorrect: ok,
explain: q?.explain || '',
})
}
return {
correct,
total: flat.length,
estimatedBand: estimateBand({ quiz, raw: correct }),
detailed,
}
}
export function estimateBand({ quiz, raw }) {
const listening = isListeningQuiz(quiz)
const score = Number(raw) || 0
// Approximate IELTS conversion (common Cambridge ranges). Works for both Reading/Listening.
const table = listening
? [
[39, 9], [37, 8.5], [35, 8], [32, 7.5], [30, 7], [26, 6.5], [23, 6], [18, 5.5],
[16, 5], [13, 4.5], [11, 4], [8, 3.5], [6, 3], [4, 2.5], [0, 2],
]
: [
[39, 9], [37, 8.5], [35, 8], [33, 7.5], [30, 7], [27, 6.5], [23, 6], [19, 5.5],
[15, 5], [13, 4.5], [10, 4], [8, 3.5], [6, 3], [4, 2.5], [0, 2],
]
for (const [min, band] of table) {
if (score >= min) return band
}
return 0
}