@intellectif/lk-core 1.3.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +59 -0
- package/README.md +2 -0
- package/dist/{ai-B222dtHH.d.ts → ai-BYryFkF9.d.cts} +462 -5
- package/dist/ai-BYryFkF9.d.cts.map +1 -0
- package/dist/{ai-B222dtHH.d.cts → ai-BYryFkF9.d.ts} +462 -5
- package/dist/ai-BYryFkF9.d.ts.map +1 -0
- package/dist/ai-check.cjs +274 -23
- package/dist/ai-check.cjs.map +1 -1
- package/dist/ai-check.d.cts +13 -5
- package/dist/ai-check.d.cts.map +1 -1
- package/dist/ai-check.d.ts +13 -5
- package/dist/ai-check.d.ts.map +1 -1
- package/dist/ai-check.js +274 -23
- package/dist/ai-check.js.map +1 -1
- package/dist/{ai-writing-DCVkv4Zj.cjs → ai-writing-Cen7-3qs.cjs} +520 -58
- package/dist/ai-writing-Cen7-3qs.cjs.map +1 -0
- package/dist/{ai-writing-CCBjTOM3.js → ai-writing-D8PdhJJz.js} +513 -75
- package/dist/ai-writing-D8PdhJJz.js.map +1 -0
- package/dist/{index-Dyu66R4-.d.cts → index-Bg0aeWtM.d.cts} +327 -3
- package/dist/index-Bg0aeWtM.d.cts.map +1 -0
- package/dist/{index-BWPRPIXL.d.ts → index-CxpiWedW.d.ts} +7 -217
- package/dist/index-CxpiWedW.d.ts.map +1 -0
- package/dist/{index-CXyOV8sm.d.cts → index-D7R3Ll8R.d.cts} +2 -2
- package/dist/{index-CXyOV8sm.d.cts.map → index-D7R3Ll8R.d.cts.map} +1 -1
- package/dist/{index-UGxRSopE.d.ts → index-DUaW1Tj5.d.ts} +327 -3
- package/dist/index-DUaW1Tj5.d.ts.map +1 -0
- package/dist/{index-O4_ExlAD.d.cts → index-qMbxed1B.d.cts} +7 -217
- package/dist/index-qMbxed1B.d.cts.map +1 -0
- package/dist/{index-CegM8o15.d.ts → index-wMc1E_aM.d.ts} +2 -2
- package/dist/{index-CegM8o15.d.ts.map → index-wMc1E_aM.d.ts.map} +1 -1
- package/dist/index.cjs +32 -130
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +115 -97
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +115 -97
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -117
- package/dist/index.js.map +1 -1
- package/dist/{item-group-DroFXgLb.cjs → item-group-DEB7nLID.cjs} +2 -2
- package/dist/{item-group-DroFXgLb.cjs.map → item-group-DEB7nLID.cjs.map} +1 -1
- package/dist/{item-group-DXiR8nOr.js → item-group-DdSUCUjM.js} +2 -2
- package/dist/{item-group-DXiR8nOr.js.map → item-group-DdSUCUjM.js.map} +1 -1
- package/dist/{registry-DVi0LR_i.cjs → registry-Ce00A_OW.cjs} +184 -4
- package/dist/registry-Ce00A_OW.cjs.map +1 -0
- package/dist/{registry-Dsx9mNsS.js → registry-DaZRpqjW.js} +155 -5
- package/dist/registry-DaZRpqjW.js.map +1 -0
- package/dist/{schemas-Bdw0nGPo.js → schemas-BioKFf3F.js} +3 -3
- package/dist/{schemas-Bdw0nGPo.js.map → schemas-BioKFf3F.js.map} +1 -1
- package/dist/{schemas-DVbAOrtd.cjs → schemas-DksueYsu.cjs} +3 -3
- package/dist/{schemas-DVbAOrtd.cjs.map → schemas-DksueYsu.cjs.map} +1 -1
- package/dist/schemas.cjs +2 -2
- package/dist/schemas.d.cts +1 -1
- package/dist/schemas.d.ts +1 -1
- package/dist/schemas.js +2 -2
- package/dist/{scoring-BZqUkuDF.js → scoring-BKNNTz-s.js} +657 -3
- package/dist/scoring-BKNNTz-s.js.map +1 -0
- package/dist/{scoring-B2_HEhMT.cjs → scoring-lKQVYsxy.cjs} +722 -2
- package/dist/scoring-lKQVYsxy.cjs.map +1 -0
- package/dist/scoring.cjs +8 -2
- package/dist/scoring.d.cts +3 -3
- package/dist/scoring.d.ts +3 -3
- package/dist/scoring.js +3 -3
- package/dist/{xapi-DNzkSJ0S.cjs → xapi-NYrTlpID.cjs} +2 -2
- package/dist/{xapi-DNzkSJ0S.cjs.map → xapi-NYrTlpID.cjs.map} +1 -1
- package/dist/{xapi-CMTph7wG.js → xapi-wR6gu4qS.js} +2 -2
- package/dist/{xapi-CMTph7wG.js.map → xapi-wR6gu4qS.js.map} +1 -1
- package/dist/xapi.cjs +1 -1
- package/dist/xapi.d.cts +1 -1
- package/dist/xapi.d.ts +1 -1
- package/dist/xapi.js +1 -2
- package/package.json +2 -2
- package/vectors/README.md +24 -1
- package/vectors/scoring.json +18182 -1
- package/dist/ai-B222dtHH.d.cts.map +0 -1
- package/dist/ai-B222dtHH.d.ts.map +0 -1
- package/dist/ai-writing-CCBjTOM3.js.map +0 -1
- package/dist/ai-writing-DCVkv4Zj.cjs.map +0 -1
- package/dist/index-BWPRPIXL.d.ts.map +0 -1
- package/dist/index-Dyu66R4-.d.cts.map +0 -1
- package/dist/index-O4_ExlAD.d.cts.map +0 -1
- package/dist/index-UGxRSopE.d.ts.map +0 -1
- package/dist/registry-DVi0LR_i.cjs.map +0 -1
- package/dist/registry-Dsx9mNsS.js.map +0 -1
- package/dist/scoring-B2_HEhMT.cjs.map +0 -1
- package/dist/scoring-BZqUkuDF.js.map +0 -1
package/dist/ai-check.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_ai_writing = require("./ai-writing-
|
|
3
|
-
const require_scoring = require("./scoring-
|
|
2
|
+
const require_ai_writing = require("./ai-writing-Cen7-3qs.cjs");
|
|
3
|
+
const require_scoring = require("./scoring-lKQVYsxy.cjs");
|
|
4
4
|
//#region src/ai-check/cases.ts
|
|
5
5
|
/**
|
|
6
6
|
* The items the cases are built from. Small, ordinary language-course content
|
|
@@ -14,7 +14,13 @@ const require_scoring = require("./scoring-B2_HEhMT.cjs");
|
|
|
14
14
|
* - a passage with more than one blank, so a hint can be about the wrong one;
|
|
15
15
|
* - a short essay whose mistakes a model must quote exactly as the learner
|
|
16
16
|
* wrote them — straight apostrophes a model likes to curl, a mistake made
|
|
17
|
-
* twice — so a correction of words nobody wrote is caught
|
|
17
|
+
* twice — so a correction of words nobody wrote is caught;
|
|
18
|
+
* - questions in item groups: a reading passage that prints a question's
|
|
19
|
+
* answer, which a hint must point to without quoting, and a run of blanks
|
|
20
|
+
* whose instructions only the group states;
|
|
21
|
+
* - essays to grade on a rubric of three criteria, two judged on levels and
|
|
22
|
+
* one on a score, so a grade that drops a criterion or leaves a scale is
|
|
23
|
+
* caught.
|
|
18
24
|
*/
|
|
19
25
|
const capital = {
|
|
20
26
|
schemaVersion: "1.0",
|
|
@@ -95,6 +101,86 @@ const listening = {
|
|
|
95
101
|
title: "Listen and type",
|
|
96
102
|
transcript: "The train leaves at half past nine."
|
|
97
103
|
};
|
|
104
|
+
/**
|
|
105
|
+
* A reading group: a passage, a question it answers word for word, and a
|
|
106
|
+
* summary of it. The question's answer is printed in the passage, so a hint
|
|
107
|
+
* that quotes the passage where it answers is refused.
|
|
108
|
+
*/
|
|
109
|
+
const TIDES = "Along most coasts the tide comes in twice a day. It is pulled by the moon: as the Earth turns, the ocean nearest the moon bulges towards it, and so does the ocean on the far side. The highest tides, called spring tides, come when the sun and the moon line up.";
|
|
110
|
+
const springTides = {
|
|
111
|
+
schemaVersion: "1.0",
|
|
112
|
+
type: "multiple-choice",
|
|
113
|
+
id: "ai-check-tides",
|
|
114
|
+
title: "Spring tides",
|
|
115
|
+
question: "When do the highest tides come?",
|
|
116
|
+
mode: "single",
|
|
117
|
+
scoringStrategy: "all-or-nothing",
|
|
118
|
+
options: [
|
|
119
|
+
{
|
|
120
|
+
id: "line-up",
|
|
121
|
+
text: "When the sun and the moon line up",
|
|
122
|
+
isCorrect: true
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
id: "full-moon",
|
|
126
|
+
text: "Only at full moon",
|
|
127
|
+
isCorrect: false
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
id: "winter",
|
|
131
|
+
text: "In winter",
|
|
132
|
+
isCorrect: false
|
|
133
|
+
}
|
|
134
|
+
]
|
|
135
|
+
};
|
|
136
|
+
const tidesSummary = {
|
|
137
|
+
schemaVersion: "1.0",
|
|
138
|
+
type: "written-response",
|
|
139
|
+
id: "ai-check-tides-summary",
|
|
140
|
+
title: "Summary",
|
|
141
|
+
prompt: "Summarise the text in one or two sentences.",
|
|
142
|
+
minWords: 10,
|
|
143
|
+
maxWords: 60,
|
|
144
|
+
languageTarget: "en-B1"
|
|
145
|
+
};
|
|
146
|
+
const tides = {
|
|
147
|
+
schemaVersion: "1.0",
|
|
148
|
+
type: "item-group",
|
|
149
|
+
id: "ai-check-tides-group",
|
|
150
|
+
title: "Part 2 — Reading",
|
|
151
|
+
stimulus: {
|
|
152
|
+
id: "ai-check-tides-text",
|
|
153
|
+
kind: "text",
|
|
154
|
+
title: "Tides",
|
|
155
|
+
body: TIDES
|
|
156
|
+
},
|
|
157
|
+
items: [springTides, tidesSummary]
|
|
158
|
+
};
|
|
159
|
+
/** A part whose questions share instructions the questions themselves never state. */
|
|
160
|
+
const formation = {
|
|
161
|
+
schemaVersion: "1.0",
|
|
162
|
+
type: "fill-in-the-blanks",
|
|
163
|
+
id: "ai-check-formation",
|
|
164
|
+
title: "Word formation",
|
|
165
|
+
passage: "She smiled {{a}} when she heard the news. (HAPPY)",
|
|
166
|
+
blanks: [{
|
|
167
|
+
id: "a",
|
|
168
|
+
acceptedAnswers: ["happily"]
|
|
169
|
+
}],
|
|
170
|
+
scoringStrategy: "all-or-nothing"
|
|
171
|
+
};
|
|
172
|
+
const formationPart = {
|
|
173
|
+
schemaVersion: "1.0",
|
|
174
|
+
type: "item-group",
|
|
175
|
+
id: "ai-check-formation-part",
|
|
176
|
+
title: "Part 1 — Word formation",
|
|
177
|
+
stimulus: {
|
|
178
|
+
id: "ai-check-formation-instructions",
|
|
179
|
+
kind: "text",
|
|
180
|
+
body: "Use the word in capitals at the end of each sentence to form a word that fits the gap."
|
|
181
|
+
},
|
|
182
|
+
items: [formation]
|
|
183
|
+
};
|
|
98
184
|
const weekend = {
|
|
99
185
|
schemaVersion: "1.0",
|
|
100
186
|
type: "written-response",
|
|
@@ -122,6 +208,117 @@ const weekend = {
|
|
|
122
208
|
}
|
|
123
209
|
] }
|
|
124
210
|
};
|
|
211
|
+
/**
|
|
212
|
+
* The weekend task set as an exam question: graded on three criteria, two on
|
|
213
|
+
* levels and one on a score. Three, so a prompt that names only the ones it
|
|
214
|
+
* expects drops one; two scales, so a grade must keep to each.
|
|
215
|
+
*/
|
|
216
|
+
const weekendExam = {
|
|
217
|
+
schemaVersion: "1.0",
|
|
218
|
+
type: "written-response",
|
|
219
|
+
id: "ai-check-writing-exam",
|
|
220
|
+
title: "Your weekend",
|
|
221
|
+
prompt: "Write a few sentences about what you did last weekend.",
|
|
222
|
+
minWords: 15,
|
|
223
|
+
maxWords: 120,
|
|
224
|
+
languageTarget: "en-A2",
|
|
225
|
+
rubric: { criteria: [
|
|
226
|
+
{
|
|
227
|
+
name: "Task",
|
|
228
|
+
description: "Says what the learner did last weekend, in order",
|
|
229
|
+
weight: 1,
|
|
230
|
+
levels: [
|
|
231
|
+
{
|
|
232
|
+
label: "Not met",
|
|
233
|
+
description: "Not about last weekend"
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
label: "Partly met",
|
|
237
|
+
description: "About the weekend, but thin or out of order"
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
label: "Met",
|
|
241
|
+
description: "Says what they did, in order"
|
|
242
|
+
}
|
|
243
|
+
]
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
name: "Grammar",
|
|
247
|
+
description: "Past tenses, articles, agreement",
|
|
248
|
+
weight: 2,
|
|
249
|
+
levels: [
|
|
250
|
+
{
|
|
251
|
+
label: "Limited",
|
|
252
|
+
description: "Errors in most sentences, some blocking meaning"
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
label: "Basic",
|
|
256
|
+
description: "Frequent errors in past tenses and articles"
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
label: "Good",
|
|
260
|
+
description: "Some errors, none that blocks meaning"
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
label: "Very good",
|
|
264
|
+
description: "Past tenses, articles and agreement almost always right"
|
|
265
|
+
}
|
|
266
|
+
]
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
name: "Vocabulary",
|
|
270
|
+
description: "Everyday words, used correctly",
|
|
271
|
+
weight: 1
|
|
272
|
+
}
|
|
273
|
+
] }
|
|
274
|
+
};
|
|
275
|
+
/** The tides summary set as an exam question, graded against its group's passage. */
|
|
276
|
+
const tidesSummaryExam = {
|
|
277
|
+
schemaVersion: "1.0",
|
|
278
|
+
type: "written-response",
|
|
279
|
+
id: "ai-check-tides-summary-exam",
|
|
280
|
+
title: "Summary",
|
|
281
|
+
prompt: "Summarise the text in one or two sentences.",
|
|
282
|
+
minWords: 10,
|
|
283
|
+
maxWords: 60,
|
|
284
|
+
languageTarget: "en-B1",
|
|
285
|
+
rubric: { criteria: [{
|
|
286
|
+
name: "Content",
|
|
287
|
+
description: "What the text says, and nothing it does not",
|
|
288
|
+
weight: 2,
|
|
289
|
+
levels: [
|
|
290
|
+
{
|
|
291
|
+
label: "Wrong",
|
|
292
|
+
description: "Misstates what the text says"
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
label: "Partly right",
|
|
296
|
+
description: "Gets one of its points wrong, or leaves it out"
|
|
297
|
+
},
|
|
298
|
+
{
|
|
299
|
+
label: "Right",
|
|
300
|
+
description: "States its points as the text does"
|
|
301
|
+
}
|
|
302
|
+
]
|
|
303
|
+
}, {
|
|
304
|
+
name: "Language",
|
|
305
|
+
description: "Clear sentences, in the learner's own words",
|
|
306
|
+
weight: 1
|
|
307
|
+
}] }
|
|
308
|
+
};
|
|
309
|
+
const tidesExam = {
|
|
310
|
+
schemaVersion: "1.0",
|
|
311
|
+
type: "item-group",
|
|
312
|
+
id: "ai-check-tides-exam",
|
|
313
|
+
title: "Part 2 — Reading",
|
|
314
|
+
stimulus: {
|
|
315
|
+
id: "ai-check-tides-exam-text",
|
|
316
|
+
kind: "text",
|
|
317
|
+
title: "Tides",
|
|
318
|
+
body: TIDES
|
|
319
|
+
},
|
|
320
|
+
items: [springTides, tidesSummaryExam]
|
|
321
|
+
};
|
|
125
322
|
const weather = {
|
|
126
323
|
schemaVersion: "1.0",
|
|
127
324
|
type: "read-aloud",
|
|
@@ -364,10 +561,11 @@ const READ_ALOUD_SETTINGS = {
|
|
|
364
561
|
}] }
|
|
365
562
|
};
|
|
366
563
|
/** Builds a case, failing loudly rather than shipping a case with no request. */
|
|
367
|
-
function explanationCase(id, about, data, response) {
|
|
564
|
+
function explanationCase(id, about, data, response, group) {
|
|
368
565
|
const request = require_ai_writing.aiExplanationRequest({
|
|
369
566
|
data,
|
|
370
|
-
response
|
|
567
|
+
response,
|
|
568
|
+
...group ? { group } : {}
|
|
371
569
|
});
|
|
372
570
|
if (request === null) throw new Error(`ai-check: no explanation request for "${id}"`);
|
|
373
571
|
return {
|
|
@@ -377,11 +575,12 @@ function explanationCase(id, about, data, response) {
|
|
|
377
575
|
request
|
|
378
576
|
};
|
|
379
577
|
}
|
|
380
|
-
function hintCase(id, about, data, response, previousHints = []) {
|
|
578
|
+
function hintCase(id, about, data, response, previousHints = [], group) {
|
|
381
579
|
const request = require_ai_writing.aiHintRequest({
|
|
382
580
|
data,
|
|
383
581
|
response,
|
|
384
|
-
previousHints
|
|
582
|
+
previousHints,
|
|
583
|
+
...group ? { group } : {}
|
|
385
584
|
});
|
|
386
585
|
if (request === null) throw new Error(`ai-check: no hint request for "${id}"`);
|
|
387
586
|
return {
|
|
@@ -391,11 +590,12 @@ function hintCase(id, about, data, response, previousHints = []) {
|
|
|
391
590
|
request
|
|
392
591
|
};
|
|
393
592
|
}
|
|
394
|
-
function writingCase(id, about, text, previousFeedback = [], learnerLocale) {
|
|
593
|
+
function writingCase(id, about, text, previousFeedback = [], learnerLocale, task = { data: weekend }) {
|
|
395
594
|
const request = require_ai_writing.aiWritingFeedbackRequest({
|
|
396
|
-
data:
|
|
595
|
+
data: task.data,
|
|
397
596
|
response: drafted(text),
|
|
398
597
|
previousFeedback,
|
|
598
|
+
...task.group ? { group: task.group } : {},
|
|
399
599
|
...learnerLocale !== void 0 ? { learnerLocale } : {}
|
|
400
600
|
});
|
|
401
601
|
if (request === null) throw new Error(`ai-check: no writing feedback request for "${id}"`);
|
|
@@ -406,6 +606,21 @@ function writingCase(id, about, text, previousFeedback = [], learnerLocale) {
|
|
|
406
606
|
request
|
|
407
607
|
};
|
|
408
608
|
}
|
|
609
|
+
function gradingCase(id, about, text, extra = {}) {
|
|
610
|
+
const built = require_ai_writing.aiGradingRequest({
|
|
611
|
+
data: extra.data ?? weekendExam,
|
|
612
|
+
response: drafted(text),
|
|
613
|
+
...extra.group ? { group: extra.group } : {},
|
|
614
|
+
...extra.learnerLocale !== void 0 ? { learnerLocale: extra.learnerLocale } : {}
|
|
615
|
+
});
|
|
616
|
+
if (!built.ok) throw new Error(`ai-check: no grading request for "${id}": ${built.problem}`);
|
|
617
|
+
return {
|
|
618
|
+
id,
|
|
619
|
+
feature: "grading",
|
|
620
|
+
about,
|
|
621
|
+
request: built.request
|
|
622
|
+
};
|
|
623
|
+
}
|
|
409
624
|
function coachingCase(id, about, marks, learnerLocale) {
|
|
410
625
|
const assessment = marks.assessment ?? forecast(true);
|
|
411
626
|
const grade = require_scoring.gradeReadAloud(weather, {
|
|
@@ -442,8 +657,9 @@ function coachingCase(id, about, marks, learnerLocale) {
|
|
|
442
657
|
/**
|
|
443
658
|
* The cases {@link runAiCheck} runs: every type the SDK explains, answered
|
|
444
659
|
* right, wrong and — where a type can be — partly right; every type it hints
|
|
445
|
-
* for, before an answer and after a wrong one;
|
|
446
|
-
* mistakes, without, and revised
|
|
660
|
+
* for, before an answer and after a wrong one; drafts of an essay, with
|
|
661
|
+
* mistakes, without, and revised; and essays to grade, on the task, with
|
|
662
|
+
* mistakes to quote, off the task, and against a passage.
|
|
447
663
|
*
|
|
448
664
|
* They are ordinary calls. What makes them a test is that the SDK knows the
|
|
449
665
|
* answer to each, so it can check what your model writes about it.
|
|
@@ -478,6 +694,7 @@ function aiCheckCases() {
|
|
|
478
694
|
})),
|
|
479
695
|
explanationCase("dictation-near", "Typed the sentence with two words wrong", listening, wrote("The train leaves at half past five")),
|
|
480
696
|
explanationCase("dictation-correct", "Typed the sentence correctly", listening, wrote("The train leaves at half past nine.")),
|
|
697
|
+
explanationCase("mc-reading-wrong", "Chose 'Only at full moon', on a question about its group's passage", springTides, chose(["full-moon"]), tides),
|
|
481
698
|
hintCase("mc-hint-1", "Has not answered yet", capital, chose([])),
|
|
482
699
|
hintCase("mc-hint-2", "Asked again after choosing Seville", capital, chose(["seville"]), ["Think about where the government sits."]),
|
|
483
700
|
hintCase("fib-hint-1", "Both blanks empty", introduction, typed({})),
|
|
@@ -487,10 +704,16 @@ function aiCheckCases() {
|
|
|
487
704
|
}), ["Look again at the first blank."]),
|
|
488
705
|
hintCase("gap-hint-1", "Neither gap chosen, in Spanish", landscape, picked({})),
|
|
489
706
|
hintCase("gap-hint-2", "Asked again with the first gap wrong", landscape, picked({ g1: "campo" }), ["Piensa en la forma del terreno."]),
|
|
707
|
+
hintCase("mc-reading-hint", "Has not answered a question whose answer its group's passage prints", springTides, chose([]), [], tides),
|
|
708
|
+
hintCase("fib-formation-hint", "A word-formation blank, under the instructions its group gives", formation, typed({}), [], formationPart),
|
|
490
709
|
writingCase("writing-mistakes", "A first draft with tense, article and agreement mistakes", "Last weekend I go to the market and buyed a apple. My friends was there too, so we don't go home early. Then I go to the cinema."),
|
|
491
710
|
writingCase("writing-clean", "A first draft with no mistakes to correct", "Last weekend I went to the market and bought an apple. My friends were there too, so we stayed until the evening. Then we went to the cinema."),
|
|
492
711
|
writingCase("writing-revised", "A second draft that fixed some mistakes", "Last weekend I went to the market and bought a apple. My friends was there too, so we didn't go home early.", ["Check your past tenses: \"go\" and \"buyed\" should be past forms."]),
|
|
493
712
|
writingCase("writing-feedback-in-spanish", "A first draft, with feedback asked for in Spanish", "Last weekend I visit my grandmother. She cook a big lunch and we eat together in the garden.", [], "es"),
|
|
713
|
+
writingCase("writing-summary", "A summary of its group's passage that gets the spring tides wrong", "The tide comes in twice a day because the moon pulls the ocean. The highest tides come only at full moon.", [], void 0, {
|
|
714
|
+
data: tidesSummary,
|
|
715
|
+
group: tides
|
|
716
|
+
}),
|
|
494
717
|
coachingCase("coaching-slips", "A reading with a mispronounced \"th\" and a word left out", { assessment: forecast(true) }),
|
|
495
718
|
coachingCase("coaching-clean", "A reading the engine marked correct throughout", { assessment: forecast(false) }),
|
|
496
719
|
coachingCase("coaching-from-grade", "The same slips, from a stored grade: marks without sounds", { fromGradeOnly: true }),
|
|
@@ -559,7 +782,15 @@ function aiCheckCases() {
|
|
|
559
782
|
locale: "en",
|
|
560
783
|
instructions: "Focus on what Maria and her grandmother buy.",
|
|
561
784
|
settings: { "read-aloud": READ_ALOUD_SETTINGS }
|
|
562
|
-
})
|
|
785
|
+
}),
|
|
786
|
+
gradingCase("grading-on-task", "An essay that does the task, with one slip in its tenses", "Last weekend I went to the market with my sister and we bought some apples. In the afternoon we watched a film at home, and on Sunday I visit my grandmother."),
|
|
787
|
+
gradingCase("grading-mistakes", "An essay with tense, article and agreement mistakes, each to quote as written", "Last weekend I go to the market and buyed a apple. My friends was there too, so we don't go home early. Then I go to the cinema."),
|
|
788
|
+
gradingCase("grading-off-task", "An essay about something other than last weekend", "My favourite food is pizza. I like it with cheese and tomato, and I eat it every Friday with my family at a small restaurant near our house."),
|
|
789
|
+
gradingCase("grading-summary", "A summary graded against its group's passage, getting the spring tides wrong", "The tide comes in twice a day because the moon pulls the ocean. The highest tides come only at full moon.", {
|
|
790
|
+
data: tidesSummaryExam,
|
|
791
|
+
group: tidesExam
|
|
792
|
+
}),
|
|
793
|
+
gradingCase("grading-in-spanish", "The essay with mistakes, with comments asked for in Spanish", "Last weekend I go to the market and buyed a apple. My friends was there too, so we don't go home early. Then I go to the cinema.", { learnerLocale: "es" })
|
|
563
794
|
];
|
|
564
795
|
}
|
|
565
796
|
//#endregion
|
|
@@ -588,6 +819,7 @@ function aiCheckCases() {
|
|
|
588
819
|
* pronunciationCoaching: (request) => callMyModel(COACHING_PROMPT, request),
|
|
589
820
|
* critique: (request) => callMyModel(CRITIQUE_PROMPT, request),
|
|
590
821
|
* drafts: (request) => callMyModel(DRAFTS_PROMPT, request),
|
|
822
|
+
* grading: (request) => callMyModel(GRADING_PROMPT, request),
|
|
591
823
|
* });
|
|
592
824
|
* console.log(formatAiCheckReport(report));
|
|
593
825
|
* if (report.refused > 0 || report.errors > 0) {
|
|
@@ -600,18 +832,27 @@ function aiCheckCases() {
|
|
|
600
832
|
* to take most seriously — that prompt gives answers away. Next come
|
|
601
833
|
* `misquotes-answer` on a writing case — that prompt corrects words the learner
|
|
602
834
|
* never wrote — and `contradicts-marks` on a coaching case: that prompt coaches
|
|
603
|
-
* words the engine heard as right, or sounds it never reported.
|
|
835
|
+
* words the engine heard as right, or sounds it never reported. On a grading
|
|
836
|
+
* case, `misses-criteria` and `out-of-scale` mean a grade nobody can use: one
|
|
837
|
+
* that leaves a criterion out grades a different task, and one off a
|
|
838
|
+
* criterion's scale grades on a scale the author did not write.
|
|
839
|
+
*
|
|
840
|
+
* A grading case the SDK accepts is a reply of the right shape, not a right
|
|
841
|
+
* grade: whether a model grades as your teachers do is what a calibration
|
|
842
|
+
* measures (`calibrationReport`), on your own responses.
|
|
604
843
|
*/
|
|
605
|
-
const REFUSALS =
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
"too-long",
|
|
609
|
-
"contradicts-grade",
|
|
610
|
-
"reveals-answer",
|
|
611
|
-
"misquotes-answer",
|
|
612
|
-
"contradicts-marks",
|
|
613
|
-
"contradicts-item"
|
|
614
|
-
|
|
844
|
+
const REFUSALS = Object.keys({
|
|
845
|
+
malformed: true,
|
|
846
|
+
empty: true,
|
|
847
|
+
"too-long": true,
|
|
848
|
+
"contradicts-grade": true,
|
|
849
|
+
"reveals-answer": true,
|
|
850
|
+
"misquotes-answer": true,
|
|
851
|
+
"contradicts-marks": true,
|
|
852
|
+
"contradicts-item": true,
|
|
853
|
+
"misses-criteria": true,
|
|
854
|
+
"out-of-scale": true
|
|
855
|
+
});
|
|
615
856
|
/** The port a case is for. */
|
|
616
857
|
function portFor(ports, one) {
|
|
617
858
|
switch (one.request.feature) {
|
|
@@ -620,6 +861,7 @@ function portFor(ports, one) {
|
|
|
620
861
|
case "pronunciation-coaching": return ports.pronunciationCoaching;
|
|
621
862
|
case "item-critique": return ports.critique;
|
|
622
863
|
case "draft-generation": return ports.drafts;
|
|
864
|
+
case "grading": return ports.grading;
|
|
623
865
|
default: return ports.writingFeedback;
|
|
624
866
|
}
|
|
625
867
|
}
|
|
@@ -642,6 +884,15 @@ async function runCase(ports, one) {
|
|
|
642
884
|
};
|
|
643
885
|
}
|
|
644
886
|
const ms = now() - started;
|
|
887
|
+
if (one.request.feature === "grading") {
|
|
888
|
+
const checked = require_ai_writing.checkAiGrading(raw, one.request);
|
|
889
|
+
return checked.ok ? {
|
|
890
|
+
case: one,
|
|
891
|
+
ok: true,
|
|
892
|
+
grading: checked.judgement,
|
|
893
|
+
ms
|
|
894
|
+
} : refused(one, raw, checked.refusal, ms);
|
|
895
|
+
}
|
|
645
896
|
if (one.request.feature === "draft-generation") {
|
|
646
897
|
let next = 0;
|
|
647
898
|
const checked = require_ai_writing.checkAiDrafts(raw, one.request, { newId: () => {
|