60 lines
1.8 KiB
TypeScript
60 lines
1.8 KiB
TypeScript
export type VocabularyRiskTestType = 'chinese-to-english' | 'audio-to-english' | 'multiple-choice';
|
|
|
|
export const DEFAULT_VOCABULARY_FULL_CORRECT_WORD_THRESHOLD = 50;
|
|
export const VOCABULARY_FULL_CORRECT_RISK_FLAG = 'large_batch_all_correct';
|
|
|
|
export const INVALIDATING_VOCABULARY_RISK_FLAGS: string[] = [
|
|
'invalid_origin',
|
|
'invalid_answer_proof',
|
|
'invalid_question_token',
|
|
'invalid_option_token',
|
|
'invalid_submitted_at',
|
|
'submitted_at_out_of_sync',
|
|
'attempt_expired',
|
|
'too_fast',
|
|
'too_slow',
|
|
'missing_choice_interaction',
|
|
'missing_input_value_trace',
|
|
'input_value_mismatch',
|
|
'uniform_answer_intervals',
|
|
'repeated_whole_second_intervals',
|
|
VOCABULARY_FULL_CORRECT_RISK_FLAG
|
|
];
|
|
|
|
const parsePositiveThreshold = (value: unknown): number | undefined => {
|
|
const parsed = Number(value);
|
|
return Number.isFinite(parsed) && parsed > 0 ? parsed : undefined;
|
|
};
|
|
|
|
export const getVocabularyFullCorrectWordThreshold = (): number => {
|
|
return parsePositiveThreshold(process.env.VOCABULARY_FULL_CORRECT_WORD_THRESHOLD) ??
|
|
DEFAULT_VOCABULARY_FULL_CORRECT_WORD_THRESHOLD;
|
|
};
|
|
|
|
export const analyzeVocabularyAttemptResultRisk = ({
|
|
testType,
|
|
totalWords,
|
|
correctWords,
|
|
threshold = getVocabularyFullCorrectWordThreshold()
|
|
}: {
|
|
testType: VocabularyRiskTestType | string;
|
|
totalWords: number;
|
|
correctWords: number;
|
|
threshold?: number;
|
|
}): string[] => {
|
|
const effectiveThreshold = parsePositiveThreshold(threshold) ??
|
|
DEFAULT_VOCABULARY_FULL_CORRECT_WORD_THRESHOLD;
|
|
const safeTotalWords = Number.isFinite(totalWords) ? totalWords : 0;
|
|
const safeCorrectWords = Number.isFinite(correctWords) ? correctWords : 0;
|
|
|
|
if (
|
|
testType !== 'multiple-choice' &&
|
|
safeTotalWords > effectiveThreshold &&
|
|
safeTotalWords === safeCorrectWords
|
|
) {
|
|
return [VOCABULARY_FULL_CORRECT_RISK_FLAG];
|
|
}
|
|
|
|
return [];
|
|
};
|