整个课程和数据UI重新设计版本
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'a0_core.dart';
|
||||
import 'courses/courses.dart';
|
||||
import 'models.dart';
|
||||
|
||||
/// A bounded AI-authored variation of an existing review item. It never
|
||||
@@ -120,6 +120,40 @@ bool matchesAdaptiveLessonAnswer(GeneratedLessonTask task, String answer) {
|
||||
return accepted || slots;
|
||||
}
|
||||
|
||||
/// Explains in Chinese why [matchesAdaptiveLessonAnswer] rejects [answer],
|
||||
/// or returns null when it accepts it. Listening answers only get a count so
|
||||
/// the explanation does not replace listening again.
|
||||
String? adaptiveAnswerShortfall(GeneratedLessonTask task, String answer) {
|
||||
if (matchesAdaptiveLessonAnswer(task, answer)) return null;
|
||||
final actual = _normalizeAnswer(answer);
|
||||
if (actual.isEmpty) return '请先输入或说出答案。';
|
||||
final spec = task.localAnswerSpec;
|
||||
final forbidden = spec.forbiddenPhrases
|
||||
.where((phrase) => _containsPhrase(actual, phrase))
|
||||
.toList();
|
||||
if (forbidden.isNotEmpty) {
|
||||
return '这里不能用:${forbidden.join('、')}。';
|
||||
}
|
||||
final missing = spec.requiredAnyPhrases
|
||||
.where(
|
||||
(alternatives) =>
|
||||
!alternatives.any((phrase) => _containsPhrase(actual, phrase)),
|
||||
)
|
||||
.toList();
|
||||
if (task.skill == 'listening') {
|
||||
return '还缺 ${missing.isEmpty ? 1 : missing.length} 处关键信息。再听一次,或慢放后补全。';
|
||||
}
|
||||
if (missing.isEmpty || answerSpecIsReferenceOnly(spec, task.answer)) {
|
||||
return '和参考表达还不一致,检查拼写和漏掉的词。';
|
||||
}
|
||||
return '还缺:${missing.map((group) => group.take(3).join(' / ')).join(';')}。';
|
||||
}
|
||||
|
||||
bool answerSpecIsReferenceOnly(GeneratedAnswerSpec spec, String answer) =>
|
||||
spec.requiredAnyPhrases.length == 1 &&
|
||||
spec.requiredAnyPhrases.single.length == 1 &&
|
||||
spec.requiredAnyPhrases.single.single == answer;
|
||||
|
||||
String _normalizeAnswer(String value) => value
|
||||
.toLowerCase()
|
||||
.replaceAll('’', "'")
|
||||
@@ -157,7 +191,7 @@ GeneratedReviewVariant? decodeGeneratedReviewVariant(
|
||||
expectedAnswer.trim().isEmpty ||
|
||||
expectedAnswer.length > 120 ||
|
||||
targetItemId != expectedTargetItemId ||
|
||||
!a0CoreItems.containsKey(targetItemId)) {
|
||||
!isCoreItem(targetItemId)) {
|
||||
return null;
|
||||
}
|
||||
return GeneratedReviewVariant(
|
||||
@@ -231,7 +265,7 @@ GeneratedLesson? decodeGeneratedLesson(
|
||||
rawTasks is! List ||
|
||||
targets.length != 1 ||
|
||||
targets.single != expectedTargetItemId ||
|
||||
!a0CoreItems.containsKey(expectedTargetItemId) ||
|
||||
!isCoreItem(expectedTargetItemId) ||
|
||||
newItems.isNotEmpty ||
|
||||
preview.isNotEmpty ||
|
||||
chunks.isNotEmpty ||
|
||||
|
||||
Reference in New Issue
Block a user