feat: 重做阅读找答案题与 AI 情境对话,并归拢本地识别、查词等既有改动
阅读"在对话里找到答案": - 16 道题全部重写,干扰项真实出现在对话里,靠说话人归属或否定句才能作答 - 选项按题目内容确定性打乱,答案不再固定排第一;听力环节同样处理 - 去掉超纲干扰项、重复题干,收紧自由作答匹配(过去单个字母也能判对) AI 情境对话: - 提示词区分"AI 这一句要做什么"与"学习者随后要完成什么",并下发已教词句清单 - JSON 只强制 reply,translation/feedback 可选;不再索要用不上的 slots/evidence - AI 不可用时页面明确提示当前回复来自内置示范脚本 - 删掉按 stage 下标猜中文翻译的兜底,避免译文与英文对不上 - 整课对话改用逐轮必需表达校验,替换"关键词沾边就算过";修正自由场景正则误伤 - 总结的"完成任务"按实际通过的轮次生成;模型点评只在结束页呈现一次 - 自由场景支持草稿续练(独立存储槽);修正回答轮数文案与永不解锁的场景标注 同时提交此前工作区中累积的改动:SenseVoice 本地识别、查词/句型解析卡、 复习与测评页调整等,并补充对话校验、选项分布和句子解析的测试。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import 'a0_core.dart';
|
||||
import 'models.dart';
|
||||
|
||||
/// Stable A0 core identities taught by each seed lesson. Wording can vary in
|
||||
@@ -533,6 +534,7 @@ class LessonActivity {
|
||||
required this.reading,
|
||||
required this.readingQuestion,
|
||||
required this.readingAnswer,
|
||||
this.readingOptions = const [],
|
||||
required this.writingPrompt,
|
||||
required this.writingExample,
|
||||
required this.independentPrompt,
|
||||
@@ -545,12 +547,39 @@ class LessonActivity {
|
||||
final String reading;
|
||||
final String readingQuestion;
|
||||
final String readingAnswer;
|
||||
final List<String> readingOptions;
|
||||
final String writingPrompt;
|
||||
final String writingExample;
|
||||
final String independentPrompt;
|
||||
final String independentHelp;
|
||||
}
|
||||
|
||||
int _seedHash(String seed) {
|
||||
var hash = 0x811c9dc5;
|
||||
for (final code in seed.codeUnits) {
|
||||
hash = ((hash ^ code) * 0x01000193) & 0x7fffffff;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
/// 选项顺序固定会让学习者养成“永远选第一个”的习惯。[options] 的第一项是标准
|
||||
/// 答案,这里按题目内容确定性地把它挪到某个位置,并打乱其余干扰项:同一道题
|
||||
/// 每次进入顺序都一样,但答案在三个位置上分布均匀。
|
||||
List<String> shuffledOptions(List<String> options, String seed) {
|
||||
if (options.length < 2) return options;
|
||||
final distractors = [...options.skip(1)];
|
||||
var hash = _seedHash(seed);
|
||||
for (var i = distractors.length - 1; i > 0; i--) {
|
||||
hash = (hash * 1103515245 + 12345) & 0x7fffffff;
|
||||
final j = hash % (i + 1);
|
||||
final swap = distractors[i];
|
||||
distractors[i] = distractors[j];
|
||||
distractors[j] = swap;
|
||||
}
|
||||
return distractors
|
||||
..insert(_seedHash('$seed#slot') % options.length, options.first);
|
||||
}
|
||||
|
||||
const a0Activities = <String, LessonActivity>{
|
||||
'a0-01': LessonActivity(
|
||||
listening: 'Hello. I’m Mia. Nice to meet you.',
|
||||
@@ -558,9 +587,14 @@ const a0Activities = <String, LessonActivity>{
|
||||
answers: ['自我介绍', '买东西', '问时间'],
|
||||
speaking: 'Hello. I’m Shen. Nice to meet you.',
|
||||
reading:
|
||||
'Mia: Hello. I’m Mia.\nShen: Hi. I’m Shen.\nMia: Nice to meet you.\nShen: Nice to meet you, too.',
|
||||
readingQuestion: '谁叫 Mia?',
|
||||
readingAnswer: '第一位说话的人',
|
||||
'Mia: Hello. I’m Mia. What’s your name?\nShen: Hi. I’m Shen.\nMia: Nice to meet you.\nShen: Nice to meet you, too.',
|
||||
readingQuestion: 'Shen 说的最后一句是什么?',
|
||||
readingAnswer: 'Nice to meet you, too.',
|
||||
readingOptions: [
|
||||
'Nice to meet you, too.',
|
||||
'What’s your name?',
|
||||
'Hi. I’m Shen.',
|
||||
],
|
||||
writingPrompt: '写一句问候和姓名介绍。',
|
||||
writingExample: 'Hello. I’m Shen.',
|
||||
independentPrompt: '不看句框,介绍你的名字并回应“Nice to meet you”。',
|
||||
@@ -572,9 +606,10 @@ const a0Activities = <String, LessonActivity>{
|
||||
answers: ['你的名字怎么拼?', '你的名字是什么?', '你来自哪里?'],
|
||||
speaking: 'S H E N',
|
||||
reading:
|
||||
'Mia: What’s your name?\nShen: Shen.\nMia: How do you spell that?\nShen: S-H-E-N.',
|
||||
readingQuestion: 'Shen 的名字怎么拼?',
|
||||
'Mia: I’m Mia. M-I-A.\nShen: Hi, Mia. I’m Shen. S-H-E-N.\nMia: How do you spell Sam?\nShen: S-A-M.',
|
||||
readingQuestion: 'Shen 自己的名字怎么拼写?',
|
||||
readingAnswer: 'S-H-E-N',
|
||||
readingOptions: ['S-H-E-N', 'M-I-A', 'S-A-M'],
|
||||
writingPrompt: '把名字和拼写写完整。',
|
||||
writingExample: 'My name is Shen.\nS-H-E-N.',
|
||||
independentPrompt: '不看句框,用英文介绍名字并拼读它。',
|
||||
@@ -586,9 +621,10 @@ const a0Activities = <String, LessonActivity>{
|
||||
answers: ['你的状态', '你的号码', '你的地点'],
|
||||
speaking: 'How are you? I’m good, thanks.',
|
||||
reading:
|
||||
'Mia: Hi, Shen. How are you?\nShen: I’m good, thanks. How are you?\nMia: I’m okay.',
|
||||
readingQuestion: 'Mia 状态如何?',
|
||||
readingAnswer: 'okay',
|
||||
'Mia: Hi, Shen. How are you?\nShen: I’m good, thanks. How are you?\nMia: I’m tired today.',
|
||||
readingQuestion: 'Mia 说自己今天怎么样?',
|
||||
readingAnswer: 'I’m tired today.',
|
||||
readingOptions: ['I’m tired today.', 'I’m good, thanks.', 'I’m okay.'],
|
||||
writingPrompt: '写一句今天的状态。',
|
||||
writingExample: 'I’m okay today.',
|
||||
independentPrompt: '不看句框,问候并说出你的状态。',
|
||||
@@ -600,9 +636,10 @@ const a0Activities = <String, LessonActivity>{
|
||||
answers: ['138', '183', '318'],
|
||||
speaking: 'My number is one-three-eight.',
|
||||
reading:
|
||||
'Mia: What’s your phone number?\nShen: One-three-eight.\nMia: Thank you.',
|
||||
readingQuestion: 'Shen 的号码是?',
|
||||
'Mia: What’s your phone number?\nShen: My number is one-three-eight.\nMia: One-eight-three?\nShen: No. One-three-eight.',
|
||||
readingQuestion: 'Shen 的号码到底是哪一个?',
|
||||
readingAnswer: '138',
|
||||
readingOptions: ['138', '183', '318'],
|
||||
writingPrompt: '把虚拟号码 139 写成英文。',
|
||||
writingExample: 'one-three-nine',
|
||||
independentPrompt: '不看句框,说出一个三位虚拟号码。',
|
||||
@@ -613,9 +650,10 @@ const a0Activities = <String, LessonActivity>{
|
||||
listeningQuestion: '这是什么?',
|
||||
answers: ['钥匙', '书', '水'],
|
||||
speaking: 'What’s this? It’s a pen.',
|
||||
reading: 'Mia: What’s this?\nShen: It’s a book.',
|
||||
readingQuestion: '这是什么?',
|
||||
readingAnswer: 'a book',
|
||||
reading: 'Mia: What’s this? Is it a pen?\nShen: No. It’s a book.',
|
||||
readingQuestion: 'Shen 说那件东西是什么?',
|
||||
readingAnswer: 'A book',
|
||||
readingOptions: ['A book', 'A pen', 'A phone'],
|
||||
writingPrompt: '写一句“这是一支笔”。',
|
||||
writingExample: 'It’s a pen.',
|
||||
independentPrompt: '不看句框,说出一个身边物品。',
|
||||
@@ -626,9 +664,11 @@ const a0Activities = <String, LessonActivity>{
|
||||
listeningQuestion: '对方在问什么?',
|
||||
answers: ['来自哪里', '叫什么', '喜欢什么'],
|
||||
speaking: 'I’m from Hong Kong.',
|
||||
reading: 'Mia: Where are you from?\nShen: I’m from Hong Kong.',
|
||||
reading:
|
||||
'Mia: I’m from London. Where are you from?\nShen: I’m from Hong Kong.',
|
||||
readingQuestion: 'Shen 来自哪里?',
|
||||
readingAnswer: 'Hong Kong',
|
||||
readingOptions: ['Hong Kong', 'London', 'Beijing'],
|
||||
writingPrompt: '写一句你来自哪里。',
|
||||
writingExample: 'I’m from Hong Kong.',
|
||||
independentPrompt: '不看句框,说来自哪里并反问对方。',
|
||||
@@ -639,9 +679,11 @@ const a0Activities = <String, LessonActivity>{
|
||||
listeningQuestion: '这个人是谁?',
|
||||
answers: ['妈妈', '朋友', '老师'],
|
||||
speaking: 'This is my family.',
|
||||
reading: 'Mia: Who is this?\nShen: This is my mother.',
|
||||
readingQuestion: 'Shen 在介绍谁?',
|
||||
readingAnswer: 'my mother',
|
||||
reading:
|
||||
'Mia: Who is this? Is this your father?\nShen: No. This is my mother.',
|
||||
readingQuestion: 'Shen 介绍的是哪一位家人?',
|
||||
readingAnswer: 'My mother',
|
||||
readingOptions: ['My mother', 'My father', 'My sister'],
|
||||
writingPrompt: '介绍一位家人或朋友。',
|
||||
writingExample: 'This is my mother.',
|
||||
independentPrompt: '不看句框,介绍一位家人或朋友。',
|
||||
@@ -652,9 +694,11 @@ const a0Activities = <String, LessonActivity>{
|
||||
listeningQuestion: '是什么时间?',
|
||||
answers: ['星期一三点', '星期三一点', '星期一一点'],
|
||||
speaking: 'It’s three o’clock.',
|
||||
reading: 'Mia: What day is it?\nShen: It’s Monday.',
|
||||
readingQuestion: '今天星期几?',
|
||||
reading:
|
||||
'Mia: What day is it today? Is it Tuesday?\nShen: No. It’s Monday.',
|
||||
readingQuestion: '对话中今天到底是星期几?',
|
||||
readingAnswer: 'Monday',
|
||||
readingOptions: ['Monday', 'Tuesday', 'Sunday'],
|
||||
writingPrompt: '写一句今天和整点。',
|
||||
writingExample: 'It’s Monday. It’s three o’clock.',
|
||||
independentPrompt: '不看句框,说今天星期几或现在几点。',
|
||||
@@ -665,9 +709,11 @@ const a0Activities = <String, LessonActivity>{
|
||||
listeningQuestion: '对方喜欢茶吗?',
|
||||
answers: ['喜欢', '不喜欢', '不知道'],
|
||||
speaking: 'I like tea. Do you like tea?',
|
||||
reading: 'Mia: I like tea. Do you like tea?\nShen: Yes, I do.',
|
||||
readingQuestion: 'Shen 的回答是什么?',
|
||||
readingAnswer: 'Yes, I do.',
|
||||
reading:
|
||||
'Mia: I like tea. Do you like tea?\nShen: No, I don’t. I like coffee.',
|
||||
readingQuestion: 'Shen 喜欢喝什么?',
|
||||
readingAnswer: 'Coffee',
|
||||
readingOptions: ['Coffee', 'Tea', 'Music'],
|
||||
writingPrompt: '写一句你的喜好。',
|
||||
writingExample: 'I like tea.',
|
||||
independentPrompt: '不看句框,说一个喜好并反问。',
|
||||
@@ -678,9 +724,11 @@ const a0Activities = <String, LessonActivity>{
|
||||
listeningQuestion: '对方希望什么?',
|
||||
answers: ['再说一遍', '说慢一点', '写下来'],
|
||||
speaking: 'Please speak slowly.',
|
||||
reading: 'Mia: Please say that again.\nShen: Please speak slowly.',
|
||||
readingQuestion: 'Shen 希望什么?',
|
||||
readingAnswer: 'speak slowly',
|
||||
reading:
|
||||
'Alex: Hi! I’m Alex. What’s your name?\nShen: Hi! I’m Shen. Nice to meet you.\nAlex: Nice to meet you, too. Where are you from?\nShen: I’m from Hong Kong. Where are you from?\nAlex: I’m from London. Do you like coffee?\nShen: No, I don’t. I like tea.',
|
||||
readingQuestion: 'Shen 来自哪里、喜欢喝什么?',
|
||||
readingAnswer: 'Hong Kong, tea',
|
||||
readingOptions: ['Hong Kong, tea', 'London, coffee', 'Hong Kong, coffee'],
|
||||
writingPrompt: '写姓名、地点和喜好三句。',
|
||||
writingExample: 'I’m Shen.\nI’m from Hong Kong.\nI like tea.',
|
||||
independentPrompt: '不看帮助,完成姓名、地点、喜好和反问。',
|
||||
@@ -699,8 +747,9 @@ const a0SegmentActivities = <String, LessonActivity>{
|
||||
answers: ['123', '132', '213'],
|
||||
speaking: 'Zero, one, two, three.',
|
||||
reading: 'Mia: One, two, three.\nShen: Four, five.',
|
||||
readingQuestion: 'Shen 说了哪两个数字?',
|
||||
readingAnswer: 'four, five',
|
||||
readingQuestion: 'Shen 接着说了哪两个数字?',
|
||||
readingAnswer: 'Four, five',
|
||||
readingOptions: ['Four, five', 'One, two', 'Three, four'],
|
||||
writingPrompt: '把 0、1、2、3 写成英文。',
|
||||
writingExample: 'zero, one, two, three',
|
||||
independentPrompt: '不看帮助,说出三个 0 到 5 的数字。',
|
||||
@@ -711,9 +760,10 @@ const a0SegmentActivities = <String, LessonActivity>{
|
||||
listeningQuestion: '听到哪一组数字?',
|
||||
answers: ['678', '687', '768'],
|
||||
speaking: 'My phone is here.',
|
||||
reading: 'Mia: What is this?\nShen: It is a phone.',
|
||||
readingQuestion: '这是什么?',
|
||||
readingAnswer: 'a phone',
|
||||
reading: 'Mia: Six, seven, eight.\nShen: Nine, ten.',
|
||||
readingQuestion: 'Shen 最后说了哪两个数字?',
|
||||
readingAnswer: 'Nine, ten',
|
||||
readingOptions: ['Nine, ten', 'Six, seven', 'Seven, eight'],
|
||||
writingPrompt: '把 6、7、8 写成英文。',
|
||||
writingExample: 'six, seven, eight',
|
||||
independentPrompt: '不看帮助,说出三个 6 到 10 的数字。',
|
||||
@@ -724,9 +774,11 @@ const a0SegmentActivities = <String, LessonActivity>{
|
||||
listeningQuestion: '号码是多少?',
|
||||
answers: ['138', '183', '318'],
|
||||
speaking: 'My number is one-three-eight.',
|
||||
reading: 'Mia: What’s your phone number?\nShen: One-three-eight.',
|
||||
readingQuestion: 'Shen 的号码是?',
|
||||
readingAnswer: '138',
|
||||
reading:
|
||||
'Mia: What’s your phone number?\nShen: My number is five-zero-two.\nMia: Five-two-zero?\nShen: No. Five-zero-two.',
|
||||
readingQuestion: 'Shen 最后确认的号码是哪一个?',
|
||||
readingAnswer: '502',
|
||||
readingOptions: ['502', '520', '205'],
|
||||
writingPrompt: '把虚拟号码 139 写成英文。',
|
||||
writingExample: 'one-three-nine',
|
||||
independentPrompt: '不看句框,说出一个三位虚拟号码。',
|
||||
@@ -737,9 +789,11 @@ const a0SegmentActivities = <String, LessonActivity>{
|
||||
listeningQuestion: '今天星期几?',
|
||||
answers: ['星期一', '星期二', '星期三'],
|
||||
speaking: 'It is Monday.',
|
||||
reading: 'Mia: What day is it?\nShen: It is Tuesday.',
|
||||
readingQuestion: '今天星期几?',
|
||||
reading:
|
||||
'Mia: What day is it today? Is it Monday?\nShen: No. It is Tuesday.',
|
||||
readingQuestion: 'Mia 猜错了,今天其实是星期几?',
|
||||
readingAnswer: 'Tuesday',
|
||||
readingOptions: ['Tuesday', 'Monday', 'Wednesday'],
|
||||
writingPrompt: '写一句今天是星期一、二或三。',
|
||||
writingExample: 'It is Monday.',
|
||||
independentPrompt: '不看帮助,说出星期一、二或三。',
|
||||
@@ -750,9 +804,10 @@ const a0SegmentActivities = <String, LessonActivity>{
|
||||
listeningQuestion: '今天星期几?',
|
||||
answers: ['星期五', '星期四', '星期日'],
|
||||
speaking: 'It is Friday.',
|
||||
reading: 'Mia: What day is it?\nShen: It is Sunday.',
|
||||
readingQuestion: '今天星期几?',
|
||||
reading: 'Mia: Is it Saturday today?\nShen: No. It is Sunday.',
|
||||
readingQuestion: 'Shen 说今天是哪一天?',
|
||||
readingAnswer: 'Sunday',
|
||||
readingOptions: ['Sunday', 'Saturday', 'Friday'],
|
||||
writingPrompt: '写一句今天是星期四到日。',
|
||||
writingExample: 'It is Friday.',
|
||||
independentPrompt: '不看帮助,说出星期四到日。',
|
||||
@@ -763,9 +818,11 @@ const a0SegmentActivities = <String, LessonActivity>{
|
||||
listeningQuestion: '是什么时间?',
|
||||
answers: ['三点', '一点', '星期三'],
|
||||
speaking: 'It is three o’clock.',
|
||||
reading: 'Mia: What time is it?\nShen: It is three o’clock.',
|
||||
readingQuestion: '几点?',
|
||||
readingAnswer: 'three o’clock',
|
||||
reading:
|
||||
'Mia: What time is it? Is it two o’clock?\nShen: No. It is three o’clock.',
|
||||
readingQuestion: 'Shen 说现在是几点?',
|
||||
readingAnswer: 'Three o’clock',
|
||||
readingOptions: ['Three o’clock', 'Two o’clock', 'One o’clock'],
|
||||
writingPrompt: '写一句整点时间。',
|
||||
writingExample: 'It is three o’clock.',
|
||||
independentPrompt: '不看帮助,说一个整点时间。',
|
||||
@@ -1072,13 +1129,116 @@ class LessonDialogue {
|
||||
required this.prompts,
|
||||
required this.hints,
|
||||
this.translations = const [],
|
||||
this.requiredTerms = const [],
|
||||
this.taskLabels = const [],
|
||||
});
|
||||
final String goal;
|
||||
final List<String> prompts;
|
||||
final List<String> hints;
|
||||
final List<String> translations;
|
||||
|
||||
/// One accepted term group per learner turn. The learner only needs to hit
|
||||
/// one term in the current group, so natural wording still passes. A term
|
||||
/// may be a plain word or phrase, an `a + b` conjunction (both parts are
|
||||
/// required), or a structural token starting with `#`.
|
||||
final List<List<String>> requiredTerms;
|
||||
|
||||
/// Chinese label of what each learner turn has to do. It drives the
|
||||
/// "还没完成本轮任务" message and the summary of completed tasks, so it must
|
||||
/// describe the task without giving away the model answer.
|
||||
final List<String> taskLabels;
|
||||
}
|
||||
|
||||
/// Matches whole words only: the old `text.contains('it')` accepted almost any
|
||||
/// sentence, including ones that never performed the task.
|
||||
bool _containsTerm(String text, String term) {
|
||||
if (term.contains(' + ')) {
|
||||
return term.split(' + ').every((part) => _containsTerm(text, part.trim()));
|
||||
}
|
||||
if (term.startsWith('#')) return _matchesStructure(text, term);
|
||||
final escaped = RegExp.escape(term.toLowerCase());
|
||||
return RegExp('(?<![a-z])$escaped(?![a-z])').hasMatch(text);
|
||||
}
|
||||
|
||||
bool _matchesStructure(String text, String token) => switch (token) {
|
||||
// Three or more letters said one by one, e.g. "S-H-E-N" or "s h e n".
|
||||
'#spelling' => RegExp(r'(?:^|[^a-z])[a-z](?:[ -][a-z]){2,}').hasMatch(text),
|
||||
// Any spoken or written digit.
|
||||
'#digit' => RegExp(
|
||||
r'(?<![a-z])(zero|one|two|three|four|five|six|seven|eight|nine|ten)(?![a-z])|[0-9]',
|
||||
).hasMatch(text),
|
||||
// A real word after the frame, so "I'm" alone is not a name.
|
||||
'#word' => RegExp(r'[a-z]{2,}').hasMatch(text),
|
||||
// Any question addressed to the partner.
|
||||
'#question' =>
|
||||
text.contains('?') ||
|
||||
RegExp(
|
||||
r"(?<![a-z])(what|where|who|when|how|why|do you|are you|can you)(?![a-z])",
|
||||
).hasMatch(text),
|
||||
_ => false,
|
||||
};
|
||||
|
||||
String _normalizeDialogueInput(String response) =>
|
||||
response.toLowerCase().replaceAll('\u2019', "'").replaceAll('\u2018', "'");
|
||||
|
||||
/// Whole-lesson and free-scene dialogues validate the same way segment
|
||||
/// dialogues do: the turn has to contain the language the turn is teaching.
|
||||
bool matchesDialogueStage(LessonDialogue script, int stage, String response) {
|
||||
final text = _normalizeDialogueInput(response);
|
||||
if (stage < 0 || stage >= script.requiredTerms.length) {
|
||||
// No declared requirement: accept anything that is actually a word.
|
||||
return RegExp(r'[a-z]{2,}').hasMatch(text);
|
||||
}
|
||||
final terms = script.requiredTerms[stage];
|
||||
if (terms.isEmpty) return RegExp(r'[a-z]{2,}').hasMatch(text);
|
||||
return terms.any((term) => _containsTerm(text, term));
|
||||
}
|
||||
|
||||
String dialogueTaskLabel(LessonDialogue script, int stage) =>
|
||||
stage >= 0 && stage < script.taskLabels.length
|
||||
? script.taskLabels[stage]
|
||||
: '完成本轮任务';
|
||||
|
||||
/// The free "初次见面" scene. It lives next to the lesson dialogues so its
|
||||
/// tasks are validated and summarised by the same rules.
|
||||
const a0MeetDialogue = LessonDialogue(
|
||||
goal: '姓名、地点、状态或喜好,并反问',
|
||||
prompts: [
|
||||
'Hi! My name is Mia. What\u2019s your name?',
|
||||
'Nice to meet you. Where are you from?',
|
||||
'Great! How are you today? Or what do you like?',
|
||||
'I\u2019m good, thanks. Now ask me one question!',
|
||||
],
|
||||
hints: [
|
||||
'My name is Alex.',
|
||||
'I\u2019m from Hong Kong.',
|
||||
'I\u2019m good, thanks. / I like coffee.',
|
||||
'What\u2019s your name? / Where are you from?',
|
||||
],
|
||||
translations: [
|
||||
'嗨!我叫 Mia。你叫什么名字?',
|
||||
'很高兴认识你。你来自哪里?',
|
||||
'很好!你今天怎么样?或者你喜欢什么?',
|
||||
'我很好,谢谢。现在请问我一个问题!',
|
||||
],
|
||||
requiredTerms: [
|
||||
["i'm + #word", 'i am + #word', 'my name is', "my name's", 'name is'],
|
||||
["i'm from", 'i am from', 'from + #word'],
|
||||
[
|
||||
'good',
|
||||
'okay',
|
||||
'ok',
|
||||
'fine',
|
||||
'great',
|
||||
'tired',
|
||||
'i like',
|
||||
'i love',
|
||||
],
|
||||
['#question'],
|
||||
],
|
||||
taskLabels: ['介绍姓名', '说明来自哪里', '表达状态或喜好', '反问对方'],
|
||||
);
|
||||
|
||||
const a0Dialogues = <String, LessonDialogue>{
|
||||
'a0-01': LessonDialogue(
|
||||
goal: '问候、介绍姓名并回应见面问候',
|
||||
@@ -1100,6 +1260,13 @@ const a0Dialogues = <String, LessonDialogue>{
|
||||
'太棒了!再打一次招呼吧。',
|
||||
'现在请问我的名字!',
|
||||
],
|
||||
requiredTerms: [
|
||||
["i'm + #word", 'i am + #word', 'my name is', "my name's", 'name is'],
|
||||
['nice to meet you'],
|
||||
['hello', 'hi', 'hey'],
|
||||
["what's your name", 'what is your name', 'your name', '#question'],
|
||||
],
|
||||
taskLabels: ['说出你的名字', '回应 Nice to meet you', '再打一次招呼', '反问对方的名字'],
|
||||
),
|
||||
'a0-02': LessonDialogue(
|
||||
goal: '介绍姓名并完整拼读名字',
|
||||
@@ -1110,12 +1277,14 @@ const a0Dialogues = <String, LessonDialogue>{
|
||||
'Now ask me my name!',
|
||||
],
|
||||
hints: ['My name is Alex.', 'A-L-E-X.', 'A-L-E-X.', 'What’s your name?'],
|
||||
translations: [
|
||||
'嗨!你叫什么名字?',
|
||||
'那个怎么拼写?',
|
||||
'谢谢。请再拼写一次。',
|
||||
'现在请问我的名字!',
|
||||
translations: ['嗨!你叫什么名字?', '那个怎么拼写?', '谢谢。请再拼写一次。', '现在请问我的名字!'],
|
||||
requiredTerms: [
|
||||
["i'm + #word", 'i am + #word', 'my name is', "my name's", 'name is'],
|
||||
['#spelling'],
|
||||
['#spelling'],
|
||||
["what's your name", 'what is your name', 'your name', '#question'],
|
||||
],
|
||||
taskLabels: ['说出你的名字', '拼读你的名字', '再拼读一次', '反问对方的名字'],
|
||||
),
|
||||
'a0-03': LessonDialogue(
|
||||
goal: '询问状态、回答并反问',
|
||||
@@ -1132,6 +1301,13 @@ const a0Dialogues = <String, LessonDialogue>{
|
||||
'我还好。请再说一次你的状态。',
|
||||
'现在请说再见!',
|
||||
],
|
||||
requiredTerms: [
|
||||
['good', 'okay', 'ok', 'fine', 'great', 'tired'],
|
||||
['how are you', '#question'],
|
||||
['good', 'okay', 'ok', 'fine', 'great', 'tired'],
|
||||
['bye', 'goodbye', 'see you'],
|
||||
],
|
||||
taskLabels: ['说出你今天的状态', '反问对方的状态', '再说一次你的状态', '说再见'],
|
||||
),
|
||||
'a0-04': LessonDialogue(
|
||||
goal: '报告一个虚拟三位号码并确认',
|
||||
@@ -1153,6 +1329,13 @@ const a0Dialogues = <String, LessonDialogue>{
|
||||
'请再说一遍这三个数字。',
|
||||
'现在请问我的电话号码!',
|
||||
],
|
||||
requiredTerms: [
|
||||
['my number is + #digit', "my number's + #digit", 'number is + #digit'],
|
||||
['yes', 'no', "that's right", 'right', 'correct'],
|
||||
['#digit'],
|
||||
["what's your phone number", 'what is your phone number', 'your phone number', 'your number'],
|
||||
],
|
||||
taskLabels: ['报出一个三位号码', '确认或纠正听到的号码', '再说一次这三个数字', '反问对方的号码'],
|
||||
),
|
||||
'a0-05': LessonDialogue(
|
||||
goal: '询问并说出一个物品',
|
||||
@@ -1169,6 +1352,13 @@ const a0Dialogues = <String, LessonDialogue>{
|
||||
'请问我:What’s this(这是什么)?',
|
||||
'太棒了!再说一个物品吧。',
|
||||
],
|
||||
requiredTerms: [
|
||||
["it's a", 'it is a', "it's an", 'it is an'],
|
||||
["it's a", 'it is a', "it's an", 'it is an'],
|
||||
["what's this", 'what is this'],
|
||||
["it's a", 'it is a', "it's an", 'it is an'],
|
||||
],
|
||||
taskLabels: ['说出这个物品', '完整说出 It’s a … 句型', '反问 What’s this', '再说一个物品'],
|
||||
),
|
||||
'a0-06': LessonDialogue(
|
||||
goal: '说来自哪里并反问',
|
||||
@@ -1190,6 +1380,13 @@ const a0Dialogues = <String, LessonDialogue>{
|
||||
'请再说一次你来自哪里。',
|
||||
'请说再见!',
|
||||
],
|
||||
requiredTerms: [
|
||||
["i'm from", 'i am from', 'from + #word'],
|
||||
['where are you from', "where're you from", 'where are you'],
|
||||
["i'm from", 'i am from', 'from + #word'],
|
||||
['bye', 'goodbye', 'see you'],
|
||||
],
|
||||
taskLabels: ['说出你来自哪里', '反问对方来自哪里', '再说一次你来自哪里', '说再见'],
|
||||
),
|
||||
'a0-07': LessonDialogue(
|
||||
goal: '介绍一位家人或朋友',
|
||||
@@ -1211,6 +1408,13 @@ const a0Dialogues = <String, LessonDialogue>{
|
||||
'请问我:Who is this(这是谁)?',
|
||||
'请再介绍一个人。',
|
||||
],
|
||||
requiredTerms: [
|
||||
['this is my', 'this is'],
|
||||
['this is my', 'this is'],
|
||||
['who is this', "who's this"],
|
||||
['this is my', 'this is'],
|
||||
],
|
||||
taskLabels: ['介绍一位家人或朋友', '完整说出 This is my … 句型', '反问 Who is this', '再介绍一个人'],
|
||||
),
|
||||
'a0-08': LessonDialogue(
|
||||
goal: '说明星期或整点',
|
||||
@@ -1226,12 +1430,14 @@ const a0Dialogues = <String, LessonDialogue>{
|
||||
'It’s three o’clock.',
|
||||
'What day is it?',
|
||||
],
|
||||
translations: [
|
||||
'今天星期几?',
|
||||
'现在几点了?',
|
||||
'请说一个完整的时间句子。',
|
||||
'现在请问我今天是星期几!',
|
||||
translations: ['今天星期几?', '现在几点了?', '请说一个完整的时间句子。', '现在请问我今天是星期几!'],
|
||||
requiredTerms: [
|
||||
['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'],
|
||||
["o'clock", 'oclock', "#digit + o'clock"],
|
||||
["it's + o'clock", "it is + o'clock", "it's + #digit", 'it is + #digit'],
|
||||
['what day is it', 'what day', '#question'],
|
||||
],
|
||||
taskLabels: ['说出今天星期几', '说出现在几点', '说一个完整的时间句子', '反问今天星期几'],
|
||||
),
|
||||
'a0-09': LessonDialogue(
|
||||
goal: '表达喜好、回答和反问',
|
||||
@@ -1242,12 +1448,14 @@ const a0Dialogues = <String, LessonDialogue>{
|
||||
'Say your like one more time.',
|
||||
],
|
||||
hints: ['I like tea.', 'Yes, I do.', 'Do you like tea?', 'I like tea.'],
|
||||
translations: [
|
||||
'你喜欢什么?',
|
||||
'你喜欢茶吗?',
|
||||
'现在请问我喜欢什么。',
|
||||
'请再说一次你的喜好。',
|
||||
translations: ['你喜欢什么?', '你喜欢茶吗?', '现在请问我喜欢什么。', '请再说一次你的喜好。'],
|
||||
requiredTerms: [
|
||||
['i like', 'i love'],
|
||||
['yes', 'no', 'i do', "i don't", 'i do not'],
|
||||
['do you like', '#question'],
|
||||
['i like', 'i love'],
|
||||
],
|
||||
taskLabels: ['说出你喜欢什么', '回答是否喜欢', '反问对方的喜好', '再说一次你的喜好'],
|
||||
),
|
||||
'a0-10': LessonDialogue(
|
||||
goal: '请求重复或放慢语速,并完成基础沟通',
|
||||
@@ -1269,6 +1477,13 @@ const a0Dialogues = <String, LessonDialogue>{
|
||||
'现在请问我的名字或我来自哪里。',
|
||||
'请说一件你喜欢的事物。',
|
||||
],
|
||||
requiredTerms: [
|
||||
['say that again', 'again', 'pardon'],
|
||||
['slowly', 'slow'],
|
||||
["what's your name", 'what is your name', 'where are you from', 'your name', '#question'],
|
||||
['i like', 'i love'],
|
||||
],
|
||||
taskLabels: ['请求对方重复', '请求对方放慢语速', '反问名字或来自哪里', '说出一件你喜欢的事物'],
|
||||
),
|
||||
};
|
||||
|
||||
@@ -1277,37 +1492,52 @@ const a0SegmentDialogues = <String, LessonDialogue>{
|
||||
goal: '听辨并说出 0 到 5',
|
||||
prompts: ['Say zero, one, two.', 'Now say three, four, five.'],
|
||||
hints: ['zero, one, two', 'three, four, five'],
|
||||
translations: ['请说 zero, one, two(0,1,2)。', '现在请说 three, four, five(3,4,5)。'],
|
||||
translations: [
|
||||
'请说 zero, one, two(0,1,2)。',
|
||||
'现在请说 three, four, five(3,4,5)。',
|
||||
],
|
||||
taskLabels: ['说出 zero, one, two', '说出 three, four, five'],
|
||||
),
|
||||
'a0-04-b': LessonDialogue(
|
||||
goal: '听辨 6 到 10 并认识 phone',
|
||||
prompts: ['Say six, seven, eight.', 'What is this? Say: It is a phone.'],
|
||||
hints: ['six, seven, eight', 'It is a phone.'],
|
||||
translations: ['请说 six, seven, eight(6,7,8)。', '这是什么?请说:It is a phone(这是一部手机)。'],
|
||||
translations: [
|
||||
'请说 six, seven, eight(6,7,8)。',
|
||||
'这是什么?请说:It is a phone(这是一部手机)。',
|
||||
],
|
||||
taskLabels: ['说出 six, seven, eight', '说出 It is a phone.'],
|
||||
),
|
||||
'a0-04-c': LessonDialogue(
|
||||
goal: '询问并报告三位号码',
|
||||
prompts: ['What is your phone number?', 'Say a three-digit number again.'],
|
||||
hints: ['My number is one-three-eight.', 'one-three-eight'],
|
||||
translations: ['你的电话号码是多少?', '请再说一次三位数字。'],
|
||||
taskLabels: ['报出你的三位号码', '再说一次三位数字'],
|
||||
),
|
||||
'a0-08-a': LessonDialogue(
|
||||
goal: '询问并说出星期一到三',
|
||||
prompts: ['What day is it?', 'Say Monday, Tuesday, or Wednesday.'],
|
||||
hints: ['What day is it?', 'It is Monday.'],
|
||||
translations: ['今天星期几?', '请说 Monday, Tuesday, 或 Wednesday(周一、周二或周三)。'],
|
||||
taskLabels: ['问今天星期几', '说出周一到周三中的一天'],
|
||||
),
|
||||
'a0-08-b': LessonDialogue(
|
||||
goal: '说出星期四到日',
|
||||
prompts: ['What day is it?', 'Say Thursday, Friday, Saturday, or Sunday.'],
|
||||
hints: ['What day is it?', 'It is Friday.'],
|
||||
translations: ['今天星期几?', '请说 Thursday, Friday, Saturday, 或 Sunday(周四、周五、周六或周日)。'],
|
||||
translations: [
|
||||
'今天星期几?',
|
||||
'请说 Thursday, Friday, Saturday, 或 Sunday(周四、周五、周六或周日)。',
|
||||
],
|
||||
taskLabels: ['问今天星期几', '说出周四到周日中的一天'],
|
||||
),
|
||||
'a0-08-c': LessonDialogue(
|
||||
goal: '询问并说出整点',
|
||||
prompts: ['What time is it?', 'Say one full time sentence.'],
|
||||
hints: ['What time is it?', 'It is three o’clock.'],
|
||||
translations: ['现在几点了?', '请说一个完整的时间句子。'],
|
||||
taskLabels: ['问现在几点', '说一个完整的时间句子'],
|
||||
),
|
||||
};
|
||||
|
||||
@@ -1315,3 +1545,21 @@ LessonDialogue dialogueByLessonId(String id) => a0Dialogues[id]!;
|
||||
|
||||
LessonDialogue dialogueBySegmentId(String segmentId, String lessonId) =>
|
||||
a0SegmentDialogues[segmentId] ?? dialogueByLessonId(lessonId);
|
||||
|
||||
/// The English a learner has actually met up to and including [lessonId].
|
||||
/// The AI partner is told to stay inside this list so a beginner never gets an
|
||||
/// answer built from words the course has not taught yet.
|
||||
List<String> taughtLanguageUpTo(String lessonId) {
|
||||
final result = <String>[];
|
||||
for (final entry in a0TargetItemIdsByLesson.entries) {
|
||||
for (final id in entry.value) {
|
||||
final word = a0CoreItems[id];
|
||||
if (word != null) result.add(word);
|
||||
}
|
||||
if (entry.key == lessonId) break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Everything A0 teaches, for the free scene that mixes all topics.
|
||||
List<String> get allTaughtLanguage => a0CoreItems.values.toList();
|
||||
|
||||
Reference in New Issue
Block a user