feat: end-to-end choice question support in assessment pipeline

- Data pathway: flow options through questions, answerKey in graph state
- Interviewer: format MULTIPLE_CHOICE with A/B/C/D options
- Grader: instant choice scoring (zero LLM), compare correctAnswer
- AssessmentView: render choice buttons vs textarea based on questionType
- Security: sanitizeStateForClient strips correctAnswer/judgment/answerKey
- Bank detection: check PUBLISHED items (not PUBLISHED bank status)
- Batch UI: select all / batch approve / batch reject on detail view
This commit is contained in:
Developer
2026-05-21 10:06:33 +08:00
parent 57898f939c
commit 3993099907
7 changed files with 228 additions and 24 deletions
@@ -67,6 +67,31 @@ export const graderNode = async (
return { currentQuestionIndex: currentQuestionIndex + 1 };
}
const isChoice = currentQuestion.questionType === 'MULTIPLE_CHOICE';
const answerKey = (state.questionAnswerKey as any)?.[currentQuestion.id];
if (isChoice || answerKey?.correctAnswer) {
const expectedAnswer = answerKey?.correctAnswer || currentQuestion.correctAnswer;
const userAnswer = (lastUserMessage.content as string).trim();
const isCorrect = userAnswer.toUpperCase() === expectedAnswer?.toUpperCase();
console.log('[GraderNode] Choice grading:', { userAnswer, expectedAnswer, isCorrect });
const feedback = isCorrect ? '✅ 正确' : `❌ 错误,正确答案是 ${expectedAnswer}`;
const feedbackMessage = new AIMessage(
{ content: `Score: ${isCorrect ? 10 : 0}\nFeedback: ${feedback}` } as any,
);
return {
messages: [feedbackMessage],
feedbackHistory: [feedbackMessage],
scores: { [currentQuestion.id || currentQuestionIndex.toString()]: isCorrect ? 10 : 0 },
shouldFollowUp: false,
followUpCount: 0,
currentQuestionIndex: currentQuestionIndex + 1,
};
}
const systemPromptZh = `你是一位专业的考官。
请根据以下问题和关键点对用户的回答进行评分。