only_ever_generator 0.4.6 → 0.4.8
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/dist/bootstrap/app.js +7 -6
- package/dist/constants/prompts/card_gen_prompt.js +49 -55
- package/dist/constants/prompts/typology_prompt.js +4 -3
- package/dist/parse/parse_source_content.js +105 -5
- package/package.json +1 -1
- package/src/bootstrap/app.ts +9 -7
- package/src/constants/prompts/card_gen_prompt.ts +49 -55
- package/src/constants/prompts/typology_prompt.ts +4 -3
- package/src/parse/parse_source_content.ts +118 -4
package/dist/bootstrap/app.js
CHANGED
|
@@ -60,10 +60,10 @@ class OnlyEverGenerator {
|
|
|
60
60
|
this.cardgenResponse = yield this.generateCard(this.promptForCardGen, JSON.stringify(this.typologyResponse), false);
|
|
61
61
|
responseToReturn.push(this.cardgenResponse);
|
|
62
62
|
/// check if gap fill is required ie coverage determination
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
63
|
+
if (this.cardgenResponse.status_code == 200) {
|
|
64
|
+
this.gapFillResponse = yield this._generationForGapFill(this.typologyResponse, this.cardgenResponse);
|
|
65
|
+
responseToReturn.push(this.gapFillResponse);
|
|
66
|
+
}
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
69
|
return responseToReturn;
|
|
@@ -85,10 +85,11 @@ class OnlyEverGenerator {
|
|
|
85
85
|
let response;
|
|
86
86
|
if (gapFill.remainingConcepts.length !== 0 ||
|
|
87
87
|
gapFill.remainingFacts.length !== 0) {
|
|
88
|
+
this.typologyResponse.facts = gapFill.remainingFacts;
|
|
89
|
+
this.typologyResponse.concepts = gapFill.remainingConcepts;
|
|
88
90
|
response = yield this.generateCard(this.promptForCardGen +
|
|
89
91
|
"Generate cards only suitable for the given remaining concepts and facts" +
|
|
90
|
-
JSON.stringify(gapFill)
|
|
91
|
-
"Exclude generating cards with content in the following", JSON.stringify(cardGenData.cards_data), true);
|
|
92
|
+
JSON.stringify(gapFill), "", true);
|
|
92
93
|
}
|
|
93
94
|
return response;
|
|
94
95
|
});
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.returnCardGenPrompt = returnCardGenPrompt;
|
|
4
|
-
const promptString = `
|
|
4
|
+
const promptString = `
|
|
5
|
+
As a dedicated assistant at a learning company, your role is to analyze educational content and create test cards that help learners understand and remember key concepts and facts. You will be provided with:
|
|
5
6
|
|
|
6
7
|
1. Title of the source
|
|
7
8
|
2. Main headings
|
|
@@ -15,7 +16,7 @@ const promptString = `As a dedicated assistant at a learning company, your role
|
|
|
15
16
|
2. Generate test cards for concepts: Take each concept and re-read the text under the reference heading for that concept. Start by trying to create a card that is at the highest bloom level possible (5 being the highest). Then work your way down to the lower bloom levels. Generate as many cards as possible for each concept. Keep going through the list of concepts till you have completed all of them.
|
|
16
17
|
3. Generate test cards for facts: Take each fact and re-read the text under the reference heading for that fact. Generate as many cards as possible to test that concept. Keep going through the list of concepts till you have completed all of them.
|
|
17
18
|
|
|
18
|
-
**Note:** Further detailed instructions on how to create the content for each test card type will be provided subsequently.
|
|
19
|
+
**Note:** Further detailed instructions on how to create the content, references and bloom level for each test card type will be provided subsequently.
|
|
19
20
|
|
|
20
21
|
**Format your response in the following JSON format:**
|
|
21
22
|
|
|
@@ -25,18 +26,12 @@ json
|
|
|
25
26
|
{
|
|
26
27
|
"type": "mcq" | "cloze" | "match",
|
|
27
28
|
"card_content": "{content}",
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
"..."
|
|
32
|
-
],
|
|
33
|
-
"facts": [
|
|
34
|
-
"fact1",
|
|
35
|
-
"fact2",
|
|
36
|
-
"..."
|
|
37
|
-
],
|
|
29
|
+
|
|
30
|
+
"concepts": [{concept1}, {concept2}, "..."],
|
|
31
|
+
"facts": [{fact1}, {fact2}, {...}],
|
|
38
32
|
"bloom_level": 1 | 2 | 3 | 4 | 5
|
|
39
|
-
}
|
|
33
|
+
},
|
|
34
|
+
{... as many as possible}
|
|
40
35
|
]
|
|
41
36
|
}
|
|
42
37
|
|
|
@@ -44,7 +39,7 @@ json
|
|
|
44
39
|
**Criteria:**
|
|
45
40
|
|
|
46
41
|
* Each test card must include at least one concept or fact.
|
|
47
|
-
* Each concept and fact
|
|
42
|
+
* Each concept and fact MUST HAVE at least one test card associated with it.
|
|
48
43
|
* The final output should include test cards that cover the first 5 levels of Bloom's Taxonomy.
|
|
49
44
|
|
|
50
45
|
**Further Instructions:**
|
|
@@ -86,23 +81,23 @@ json
|
|
|
86
81
|
[
|
|
87
82
|
{
|
|
88
83
|
"concept_text": "concept1_content",
|
|
89
|
-
"reference": "
|
|
84
|
+
"reference": "main_heading"
|
|
90
85
|
},
|
|
91
86
|
{
|
|
92
87
|
"concept_text": "concept2_content",
|
|
93
|
-
"reference": "
|
|
88
|
+
"reference": "main_heading"
|
|
94
89
|
},
|
|
95
90
|
{...}
|
|
96
91
|
],
|
|
97
92
|
"facts":
|
|
98
93
|
[
|
|
99
94
|
{
|
|
100
|
-
"
|
|
101
|
-
"reference": "
|
|
95
|
+
"fact_text": "fact1_content",
|
|
96
|
+
"reference": "main_heading"
|
|
102
97
|
},
|
|
103
98
|
{
|
|
104
99
|
"fact_text": "fact2_content",
|
|
105
|
-
"reference": "
|
|
100
|
+
"reference": "main_heading"
|
|
106
101
|
},
|
|
107
102
|
{...}
|
|
108
103
|
],
|
|
@@ -135,92 +130,91 @@ json
|
|
|
135
130
|
[
|
|
136
131
|
{
|
|
137
132
|
"concept_text": "concept1_content",
|
|
138
|
-
"reference": "
|
|
133
|
+
"reference": "main_heading"
|
|
139
134
|
},
|
|
140
135
|
{
|
|
141
136
|
"concept_text": "concept2_content",
|
|
142
|
-
"reference": "
|
|
137
|
+
"reference": "main_heading"
|
|
143
138
|
},
|
|
144
139
|
{...}
|
|
145
140
|
],
|
|
146
141
|
"facts":
|
|
147
142
|
[
|
|
148
143
|
{
|
|
149
|
-
"
|
|
150
|
-
"reference": "
|
|
144
|
+
"fact_text": "fact1_content",
|
|
145
|
+
"reference": "main_heading"
|
|
151
146
|
},
|
|
152
147
|
{
|
|
153
148
|
"fact_text": "fact2_content",
|
|
154
|
-
"reference": "
|
|
149
|
+
"reference": "main_heading"
|
|
155
150
|
},
|
|
156
151
|
{...}
|
|
157
152
|
],
|
|
158
153
|
"bloom_level": <1-5>
|
|
159
154
|
}
|
|
160
155
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
156
|
+
* Minimum choices required: 2
|
|
157
|
+
* Maximum choices allowed: 8
|
|
158
|
+
* Minimum correct choices required: 1
|
|
159
|
+
* Maximum character length for the prompt: 320
|
|
160
|
+
* Maximum character length for an individual cloze: 90
|
|
166
161
|
|
|
167
162
|
4. Match: Pairing items.
|
|
168
163
|
|
|
169
164
|
json
|
|
170
165
|
{
|
|
171
166
|
"type": "match",
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
"
|
|
183
|
-
|
|
184
|
-
},
|
|
185
|
-
"... up to 8 total pairs"
|
|
186
|
-
],
|
|
167
|
+
|
|
168
|
+
"card_content" : [
|
|
169
|
+
{
|
|
170
|
+
"left_item" : "left_item text",
|
|
171
|
+
"right_item" : ["right_item text" ]
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
"left_item" : "left_item text",
|
|
175
|
+
"right_item" : ["right_item text"]
|
|
176
|
+
},
|
|
177
|
+
{"... up to 8 total pairs"}
|
|
178
|
+
],
|
|
187
179
|
"concepts":
|
|
188
180
|
[
|
|
189
181
|
{
|
|
190
182
|
"concept_text": "concept1_content",
|
|
191
|
-
"reference": "
|
|
183
|
+
"reference": "main_heading"
|
|
192
184
|
},
|
|
193
185
|
{
|
|
194
186
|
"concept_text": "concept2_content",
|
|
195
|
-
"reference": "
|
|
187
|
+
"reference": "main_heading"
|
|
196
188
|
},
|
|
197
189
|
{...}
|
|
198
190
|
],
|
|
199
191
|
"facts":
|
|
200
192
|
[
|
|
201
193
|
{
|
|
202
|
-
"
|
|
203
|
-
"reference": "
|
|
194
|
+
"fact_text": "fact1_content",
|
|
195
|
+
"reference": "main_heading"
|
|
204
196
|
},
|
|
205
197
|
{
|
|
206
198
|
"fact_text": "fact2_content",
|
|
207
|
-
"reference": "
|
|
199
|
+
"reference": "main_heading"
|
|
208
200
|
},
|
|
209
201
|
{...}
|
|
210
202
|
],
|
|
211
203
|
"bloom_level": <1-5>
|
|
212
204
|
}
|
|
213
205
|
|
|
214
|
-
|
|
206
|
+
* Maximum character length for each item in a pair: 42
|
|
207
|
+
* Duplicate items are allowed on the left side but not on the right side. Or in other words the same item on the left can be paired with multiple items on the right.
|
|
215
208
|
|
|
216
209
|
|
|
217
|
-
** Criteria **
|
|
218
210
|
|
|
219
|
-
|
|
220
|
-
2. For each concept and fact start by trying to create a card at the highest bloom level possible.
|
|
221
|
-
3. Do not skip any concepts or facts, and be thorough in your coverage.
|
|
222
|
-
4. Cards should span across different levels of Bloom’s Taxonomy, from level 1 (Remembering) to level 5 (Evaluating), but exclude level 6 (Creating)
|
|
211
|
+
** Overall Criteria for Testing Cards **
|
|
223
212
|
|
|
213
|
+
1. Each card should present the learner with a unique challenge that improves their learning.
|
|
214
|
+
2. Ensure that you produce at least one if not more card for each concept and fact.
|
|
215
|
+
3. For each concept and fact start by trying to create a card at the highest bloom level possible.
|
|
216
|
+
4. Do not skip any concepts or facts, and be thorough in your coverage.
|
|
217
|
+
5. Cards should span across different levels of Bloom’s Taxonomy, from level 1 (Remembering) to level 5 (Evaluating), but exclude level 6 (Creating).
|
|
224
218
|
Once you are done generating the test cards. Go back and evaulate the full list of concepts and facts provided as the input.
|
|
225
219
|
|
|
226
220
|
Are there any concept or fact that don't have a test card yet? If yes, go back and create one.
|
|
@@ -64,7 +64,7 @@ Extract key concepts within the content after classifying the field. This is a c
|
|
|
64
64
|
2. **Inclusion Criteria**: Include a concept only if it is discussed in detail, meaning it is explained thoroughly, tied to specific examples, or highlighted as a critical part of the subject matter.
|
|
65
65
|
3. **How to describe a concept**: The concept should be described so that a reader can comprehend the gist of it.
|
|
66
66
|
4. **Character Limit**: Maintain a limit of 60 characters for the to ensure each concept is concise yet informative.
|
|
67
|
-
5. **Reference**: Every concept must include a reference. A reference can either be the entire source or a specific heading in the source.
|
|
67
|
+
5. **Reference**: Every concept must include a reference. A reference can either be the entire source or a specific heading in the source. Whenever possible, pick a main heading to direct the user to the most relevant part of the source material. The heading must exactly match one of the headings provided to you. Sometimes concepts may need to reference the entire text or multiple headings, leave the reference empty for such cases.
|
|
68
68
|
|
|
69
69
|
List the concepts in the following JSON format:
|
|
70
70
|
|
|
@@ -83,9 +83,10 @@ After classifying the content and identifying key concepts, proceed to extract a
|
|
|
83
83
|
1. **Definition of a Fact**: Ensure each fact is a standalone piece of information that is concrete and can be independently verified.
|
|
84
84
|
2. **Selection Criteria**: Choose facts based on their significance to the content's main themes or concepts, their educational value, or their foundational role in the subject.
|
|
85
85
|
3. **Character Limit**: Maintain a limit of 60 characters for the to ensure each message is concise yet informative.
|
|
86
|
-
4. **Reference**: Every fact must include a reference.
|
|
86
|
+
4. **Reference**: Every fact must include a reference. A reference can either be the entire source or a specific heading in the source. Whenever possible, pick a main heading to direct the user to the most relevant part of the source material. The heading must exactly match one of the headings provided to you. Sometimes facts may need to reference the entire text or multiple headings, leave the reference empty for such cases.
|
|
87
87
|
|
|
88
88
|
List the facts in the following JSON format:
|
|
89
|
+
|
|
89
90
|
json
|
|
90
91
|
"facts":
|
|
91
92
|
[
|
|
@@ -95,6 +96,7 @@ json
|
|
|
95
96
|
},
|
|
96
97
|
{...}
|
|
97
98
|
]
|
|
99
|
+
|
|
98
100
|
After analyzing the content, classifying its field, and identifying key concepts, and facts, assess whether the discovered elements warrant the creation of testing (quiz) materials.
|
|
99
101
|
|
|
100
102
|
Consider if these elements provide significant educational value to an average learner by enhancing understanding, offering practical applications, or supporting crucial educational goals. If you decide that the source does not hold educational value that is worthy of generating testing material or quizzes for then please provide a reason in less than 90 characters.
|
|
@@ -128,7 +130,6 @@ json
|
|
|
128
130
|
"summary_cards": ["summary_card1_content", "summary_card2_content", "summary_card3_content", "..."]
|
|
129
131
|
}
|
|
130
132
|
|
|
131
|
-
|
|
132
133
|
`;
|
|
133
134
|
function returnTypologyPrompt() {
|
|
134
135
|
return typologyPromptString;
|
|
@@ -3,14 +3,29 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.ParseSourceContent = void 0;
|
|
4
4
|
class ParseSourceContent {
|
|
5
5
|
constructor(sourceContent) {
|
|
6
|
+
/// Format of Content
|
|
7
|
+
// content: {
|
|
8
|
+
// title: source.title,
|
|
9
|
+
// headings: source.headings,
|
|
10
|
+
// content: source.content,
|
|
11
|
+
// fields: fields,
|
|
12
|
+
// taxonomy: source.source_taxonomy,
|
|
13
|
+
// type: source.source_type
|
|
14
|
+
// },
|
|
6
15
|
this.titles_to_remove = ['See also', 'References', 'Further reading', 'External links', 'Notes and references', 'Bibliography', 'Notes', 'Cited sources'];
|
|
7
16
|
this.block_types_toremove = ['table', 'empty_line'];
|
|
8
17
|
this.content = sourceContent;
|
|
9
18
|
}
|
|
10
19
|
parseData() {
|
|
11
|
-
|
|
12
|
-
let
|
|
13
|
-
|
|
20
|
+
let sourceType = this.content.type;
|
|
21
|
+
let afterSanitized;
|
|
22
|
+
if (sourceType == "video") {
|
|
23
|
+
afterSanitized = this.parseVideoContent(this.content.content);
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
let dataAfterRemovingUnWantedBlocks = this.removeSectionsByTitle(this.content.content);
|
|
27
|
+
afterSanitized = this.sanitizeBlocks(dataAfterRemovingUnWantedBlocks);
|
|
28
|
+
}
|
|
14
29
|
return {
|
|
15
30
|
type: this.content.type,
|
|
16
31
|
title: this.content.title,
|
|
@@ -36,7 +51,7 @@ class ParseSourceContent {
|
|
|
36
51
|
}
|
|
37
52
|
return dataAfterRemoving;
|
|
38
53
|
}
|
|
39
|
-
|
|
54
|
+
sanitizeTextContent(content) {
|
|
40
55
|
// Remove newline characters
|
|
41
56
|
content = content.replace(/\\n/g, ' ');
|
|
42
57
|
// Remove internal link references, keeping only the link text
|
|
@@ -58,7 +73,7 @@ class ParseSourceContent {
|
|
|
58
73
|
for (let key in block) {
|
|
59
74
|
let value = block[key];
|
|
60
75
|
if (typeof value === 'string') {
|
|
61
|
-
sanitizedBlock[key] = this.
|
|
76
|
+
sanitizedBlock[key] = this.sanitizeTextContent(value);
|
|
62
77
|
}
|
|
63
78
|
else if (Array.isArray(value)) {
|
|
64
79
|
sanitizedBlock[key] = this.sanitizeBlocks(value);
|
|
@@ -71,5 +86,90 @@ class ParseSourceContent {
|
|
|
71
86
|
});
|
|
72
87
|
return sanitizedBlocks;
|
|
73
88
|
}
|
|
89
|
+
parseVideoContent(data) {
|
|
90
|
+
let timeCodes = [];
|
|
91
|
+
data.map((e) => timeCodes.push(...e.children));
|
|
92
|
+
let cleanedData = this.cleanTranscript(timeCodes);
|
|
93
|
+
let collapsedData = this.collapseTimeCodes(cleanedData, 100);
|
|
94
|
+
return collapsedData;
|
|
95
|
+
}
|
|
96
|
+
// remove content inside [] which denotes non-speech sounds
|
|
97
|
+
isNonSpeech(content) {
|
|
98
|
+
// Check if the content is non-speech (enclosed in square brackets).
|
|
99
|
+
return /^\[.*\]$/.test(content.trim());
|
|
100
|
+
}
|
|
101
|
+
// remove non-essential content
|
|
102
|
+
cleanTranscript(data) {
|
|
103
|
+
// Clean the transcript by removing non-speech content, normalizing whitespace, and keeping only necessary fields.
|
|
104
|
+
const cleanedData = [];
|
|
105
|
+
data.forEach(entry => {
|
|
106
|
+
let content = (entry.content || '').trim();
|
|
107
|
+
// Skip non-speech content
|
|
108
|
+
if (this.isNonSpeech(content))
|
|
109
|
+
return;
|
|
110
|
+
// Normalize whitespace in content
|
|
111
|
+
content = content.replace(/\s+/g, ' ');
|
|
112
|
+
// Only keep start_time, end_time, content
|
|
113
|
+
const currentEntry = {
|
|
114
|
+
start_time: entry.startTime,
|
|
115
|
+
end_time: entry.endTime,
|
|
116
|
+
content: content
|
|
117
|
+
};
|
|
118
|
+
cleanedData.push(currentEntry);
|
|
119
|
+
});
|
|
120
|
+
return cleanedData;
|
|
121
|
+
}
|
|
122
|
+
// collapse the timecode to 30 seconds
|
|
123
|
+
collapseTimeCodes(data, maxDuration = 30.0) {
|
|
124
|
+
// Collapse time codes into buckets of approximately maxDuration seconds.
|
|
125
|
+
const collapsedData = [];
|
|
126
|
+
let bucketStartTime = null;
|
|
127
|
+
let bucketEndTime = null;
|
|
128
|
+
let bucketContent = [];
|
|
129
|
+
let bucketDuration = 0.0;
|
|
130
|
+
data.forEach(entry => {
|
|
131
|
+
const startTime = entry.start_time;
|
|
132
|
+
const endTime = entry.end_time;
|
|
133
|
+
const content = entry.content;
|
|
134
|
+
const entryDuration = endTime - startTime;
|
|
135
|
+
if (bucketStartTime === null) {
|
|
136
|
+
// Start a new bucket
|
|
137
|
+
bucketStartTime = startTime;
|
|
138
|
+
bucketEndTime = endTime;
|
|
139
|
+
bucketContent.push(content);
|
|
140
|
+
bucketDuration = entryDuration;
|
|
141
|
+
}
|
|
142
|
+
else if ((bucketDuration + entryDuration) <= maxDuration) {
|
|
143
|
+
// Add to current bucket
|
|
144
|
+
bucketEndTime = endTime;
|
|
145
|
+
bucketContent.push(content);
|
|
146
|
+
bucketDuration += entryDuration;
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
// Close current bucket and start a new one
|
|
150
|
+
const collapsedEntry = {
|
|
151
|
+
start_time: bucketStartTime,
|
|
152
|
+
end_time: bucketEndTime,
|
|
153
|
+
content: bucketContent.join(' ')
|
|
154
|
+
};
|
|
155
|
+
collapsedData.push(collapsedEntry);
|
|
156
|
+
// Start new bucket with current entry
|
|
157
|
+
bucketStartTime = startTime;
|
|
158
|
+
bucketEndTime = endTime;
|
|
159
|
+
bucketContent = [content];
|
|
160
|
+
bucketDuration = entryDuration;
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
// Add the last bucket if it exists
|
|
164
|
+
if (bucketContent.length > 0) {
|
|
165
|
+
const collapsedEntry = {
|
|
166
|
+
start_time: bucketStartTime,
|
|
167
|
+
end_time: bucketEndTime,
|
|
168
|
+
content: bucketContent.join(' ')
|
|
169
|
+
};
|
|
170
|
+
collapsedData.push(collapsedEntry);
|
|
171
|
+
}
|
|
172
|
+
return collapsedData;
|
|
173
|
+
}
|
|
74
174
|
}
|
|
75
175
|
exports.ParseSourceContent = ParseSourceContent;
|
package/package.json
CHANGED
package/src/bootstrap/app.ts
CHANGED
|
@@ -78,10 +78,10 @@ export class OnlyEverGenerator {
|
|
|
78
78
|
responseToReturn.push(this.cardgenResponse);
|
|
79
79
|
|
|
80
80
|
/// check if gap fill is required ie coverage determination
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
81
|
+
if(this.cardgenResponse.status_code == 200) {
|
|
82
|
+
this.gapFillResponse = await this._generationForGapFill(this.typologyResponse, this.cardgenResponse);
|
|
83
|
+
responseToReturn.push(this.gapFillResponse);
|
|
84
|
+
}
|
|
85
85
|
|
|
86
86
|
}
|
|
87
87
|
}
|
|
@@ -106,12 +106,14 @@ export class OnlyEverGenerator {
|
|
|
106
106
|
gapFill.remainingConcepts.length !== 0 ||
|
|
107
107
|
gapFill.remainingFacts.length !== 0
|
|
108
108
|
) {
|
|
109
|
+
this.typologyResponse.facts = gapFill.remainingFacts;
|
|
110
|
+
this.typologyResponse.concepts = gapFill.remainingConcepts;
|
|
109
111
|
response = await this.generateCard(
|
|
110
112
|
this.promptForCardGen +
|
|
111
113
|
"Generate cards only suitable for the given remaining concepts and facts" +
|
|
112
|
-
JSON.stringify(gapFill)
|
|
113
|
-
|
|
114
|
-
|
|
114
|
+
JSON.stringify(gapFill) ,
|
|
115
|
+
|
|
116
|
+
"",
|
|
115
117
|
true
|
|
116
118
|
);
|
|
117
119
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
const promptString: string = `
|
|
1
|
+
const promptString: string = `
|
|
2
|
+
As a dedicated assistant at a learning company, your role is to analyze educational content and create test cards that help learners understand and remember key concepts and facts. You will be provided with:
|
|
2
3
|
|
|
3
4
|
1. Title of the source
|
|
4
5
|
2. Main headings
|
|
@@ -12,7 +13,7 @@ const promptString: string = `As a dedicated assistant at a learning company, yo
|
|
|
12
13
|
2. Generate test cards for concepts: Take each concept and re-read the text under the reference heading for that concept. Start by trying to create a card that is at the highest bloom level possible (5 being the highest). Then work your way down to the lower bloom levels. Generate as many cards as possible for each concept. Keep going through the list of concepts till you have completed all of them.
|
|
13
14
|
3. Generate test cards for facts: Take each fact and re-read the text under the reference heading for that fact. Generate as many cards as possible to test that concept. Keep going through the list of concepts till you have completed all of them.
|
|
14
15
|
|
|
15
|
-
**Note:** Further detailed instructions on how to create the content for each test card type will be provided subsequently.
|
|
16
|
+
**Note:** Further detailed instructions on how to create the content, references and bloom level for each test card type will be provided subsequently.
|
|
16
17
|
|
|
17
18
|
**Format your response in the following JSON format:**
|
|
18
19
|
|
|
@@ -22,18 +23,12 @@ json
|
|
|
22
23
|
{
|
|
23
24
|
"type": "mcq" | "cloze" | "match",
|
|
24
25
|
"card_content": "{content}",
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
"..."
|
|
29
|
-
],
|
|
30
|
-
"facts": [
|
|
31
|
-
"fact1",
|
|
32
|
-
"fact2",
|
|
33
|
-
"..."
|
|
34
|
-
],
|
|
26
|
+
|
|
27
|
+
"concepts": [{concept1}, {concept2}, "..."],
|
|
28
|
+
"facts": [{fact1}, {fact2}, {...}],
|
|
35
29
|
"bloom_level": 1 | 2 | 3 | 4 | 5
|
|
36
|
-
}
|
|
30
|
+
},
|
|
31
|
+
{... as many as possible}
|
|
37
32
|
]
|
|
38
33
|
}
|
|
39
34
|
|
|
@@ -41,7 +36,7 @@ json
|
|
|
41
36
|
**Criteria:**
|
|
42
37
|
|
|
43
38
|
* Each test card must include at least one concept or fact.
|
|
44
|
-
* Each concept and fact
|
|
39
|
+
* Each concept and fact MUST HAVE at least one test card associated with it.
|
|
45
40
|
* The final output should include test cards that cover the first 5 levels of Bloom's Taxonomy.
|
|
46
41
|
|
|
47
42
|
**Further Instructions:**
|
|
@@ -83,23 +78,23 @@ json
|
|
|
83
78
|
[
|
|
84
79
|
{
|
|
85
80
|
"concept_text": "concept1_content",
|
|
86
|
-
"reference": "
|
|
81
|
+
"reference": "main_heading"
|
|
87
82
|
},
|
|
88
83
|
{
|
|
89
84
|
"concept_text": "concept2_content",
|
|
90
|
-
"reference": "
|
|
85
|
+
"reference": "main_heading"
|
|
91
86
|
},
|
|
92
87
|
{...}
|
|
93
88
|
],
|
|
94
89
|
"facts":
|
|
95
90
|
[
|
|
96
91
|
{
|
|
97
|
-
"
|
|
98
|
-
"reference": "
|
|
92
|
+
"fact_text": "fact1_content",
|
|
93
|
+
"reference": "main_heading"
|
|
99
94
|
},
|
|
100
95
|
{
|
|
101
96
|
"fact_text": "fact2_content",
|
|
102
|
-
"reference": "
|
|
97
|
+
"reference": "main_heading"
|
|
103
98
|
},
|
|
104
99
|
{...}
|
|
105
100
|
],
|
|
@@ -132,92 +127,91 @@ json
|
|
|
132
127
|
[
|
|
133
128
|
{
|
|
134
129
|
"concept_text": "concept1_content",
|
|
135
|
-
"reference": "
|
|
130
|
+
"reference": "main_heading"
|
|
136
131
|
},
|
|
137
132
|
{
|
|
138
133
|
"concept_text": "concept2_content",
|
|
139
|
-
"reference": "
|
|
134
|
+
"reference": "main_heading"
|
|
140
135
|
},
|
|
141
136
|
{...}
|
|
142
137
|
],
|
|
143
138
|
"facts":
|
|
144
139
|
[
|
|
145
140
|
{
|
|
146
|
-
"
|
|
147
|
-
"reference": "
|
|
141
|
+
"fact_text": "fact1_content",
|
|
142
|
+
"reference": "main_heading"
|
|
148
143
|
},
|
|
149
144
|
{
|
|
150
145
|
"fact_text": "fact2_content",
|
|
151
|
-
"reference": "
|
|
146
|
+
"reference": "main_heading"
|
|
152
147
|
},
|
|
153
148
|
{...}
|
|
154
149
|
],
|
|
155
150
|
"bloom_level": <1-5>
|
|
156
151
|
}
|
|
157
152
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
153
|
+
* Minimum choices required: 2
|
|
154
|
+
* Maximum choices allowed: 8
|
|
155
|
+
* Minimum correct choices required: 1
|
|
156
|
+
* Maximum character length for the prompt: 320
|
|
157
|
+
* Maximum character length for an individual cloze: 90
|
|
163
158
|
|
|
164
159
|
4. Match: Pairing items.
|
|
165
160
|
|
|
166
161
|
json
|
|
167
162
|
{
|
|
168
163
|
"type": "match",
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
"
|
|
180
|
-
|
|
181
|
-
},
|
|
182
|
-
"... up to 8 total pairs"
|
|
183
|
-
],
|
|
164
|
+
|
|
165
|
+
"card_content" : [
|
|
166
|
+
{
|
|
167
|
+
"left_item" : "left_item text",
|
|
168
|
+
"right_item" : ["right_item text" ]
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
"left_item" : "left_item text",
|
|
172
|
+
"right_item" : ["right_item text"]
|
|
173
|
+
},
|
|
174
|
+
{"... up to 8 total pairs"}
|
|
175
|
+
],
|
|
184
176
|
"concepts":
|
|
185
177
|
[
|
|
186
178
|
{
|
|
187
179
|
"concept_text": "concept1_content",
|
|
188
|
-
"reference": "
|
|
180
|
+
"reference": "main_heading"
|
|
189
181
|
},
|
|
190
182
|
{
|
|
191
183
|
"concept_text": "concept2_content",
|
|
192
|
-
"reference": "
|
|
184
|
+
"reference": "main_heading"
|
|
193
185
|
},
|
|
194
186
|
{...}
|
|
195
187
|
],
|
|
196
188
|
"facts":
|
|
197
189
|
[
|
|
198
190
|
{
|
|
199
|
-
"
|
|
200
|
-
"reference": "
|
|
191
|
+
"fact_text": "fact1_content",
|
|
192
|
+
"reference": "main_heading"
|
|
201
193
|
},
|
|
202
194
|
{
|
|
203
195
|
"fact_text": "fact2_content",
|
|
204
|
-
"reference": "
|
|
196
|
+
"reference": "main_heading"
|
|
205
197
|
},
|
|
206
198
|
{...}
|
|
207
199
|
],
|
|
208
200
|
"bloom_level": <1-5>
|
|
209
201
|
}
|
|
210
202
|
|
|
211
|
-
|
|
203
|
+
* Maximum character length for each item in a pair: 42
|
|
204
|
+
* Duplicate items are allowed on the left side but not on the right side. Or in other words the same item on the left can be paired with multiple items on the right.
|
|
212
205
|
|
|
213
206
|
|
|
214
|
-
** Criteria **
|
|
215
207
|
|
|
216
|
-
|
|
217
|
-
2. For each concept and fact start by trying to create a card at the highest bloom level possible.
|
|
218
|
-
3. Do not skip any concepts or facts, and be thorough in your coverage.
|
|
219
|
-
4. Cards should span across different levels of Bloom’s Taxonomy, from level 1 (Remembering) to level 5 (Evaluating), but exclude level 6 (Creating)
|
|
208
|
+
** Overall Criteria for Testing Cards **
|
|
220
209
|
|
|
210
|
+
1. Each card should present the learner with a unique challenge that improves their learning.
|
|
211
|
+
2. Ensure that you produce at least one if not more card for each concept and fact.
|
|
212
|
+
3. For each concept and fact start by trying to create a card at the highest bloom level possible.
|
|
213
|
+
4. Do not skip any concepts or facts, and be thorough in your coverage.
|
|
214
|
+
5. Cards should span across different levels of Bloom’s Taxonomy, from level 1 (Remembering) to level 5 (Evaluating), but exclude level 6 (Creating).
|
|
221
215
|
Once you are done generating the test cards. Go back and evaulate the full list of concepts and facts provided as the input.
|
|
222
216
|
|
|
223
217
|
Are there any concept or fact that don't have a test card yet? If yes, go back and create one.
|
|
@@ -61,7 +61,7 @@ Extract key concepts within the content after classifying the field. This is a c
|
|
|
61
61
|
2. **Inclusion Criteria**: Include a concept only if it is discussed in detail, meaning it is explained thoroughly, tied to specific examples, or highlighted as a critical part of the subject matter.
|
|
62
62
|
3. **How to describe a concept**: The concept should be described so that a reader can comprehend the gist of it.
|
|
63
63
|
4. **Character Limit**: Maintain a limit of 60 characters for the to ensure each concept is concise yet informative.
|
|
64
|
-
5. **Reference**: Every concept must include a reference. A reference can either be the entire source or a specific heading in the source.
|
|
64
|
+
5. **Reference**: Every concept must include a reference. A reference can either be the entire source or a specific heading in the source. Whenever possible, pick a main heading to direct the user to the most relevant part of the source material. The heading must exactly match one of the headings provided to you. Sometimes concepts may need to reference the entire text or multiple headings, leave the reference empty for such cases.
|
|
65
65
|
|
|
66
66
|
List the concepts in the following JSON format:
|
|
67
67
|
|
|
@@ -80,9 +80,10 @@ After classifying the content and identifying key concepts, proceed to extract a
|
|
|
80
80
|
1. **Definition of a Fact**: Ensure each fact is a standalone piece of information that is concrete and can be independently verified.
|
|
81
81
|
2. **Selection Criteria**: Choose facts based on their significance to the content's main themes or concepts, their educational value, or their foundational role in the subject.
|
|
82
82
|
3. **Character Limit**: Maintain a limit of 60 characters for the to ensure each message is concise yet informative.
|
|
83
|
-
4. **Reference**: Every fact must include a reference.
|
|
83
|
+
4. **Reference**: Every fact must include a reference. A reference can either be the entire source or a specific heading in the source. Whenever possible, pick a main heading to direct the user to the most relevant part of the source material. The heading must exactly match one of the headings provided to you. Sometimes facts may need to reference the entire text or multiple headings, leave the reference empty for such cases.
|
|
84
84
|
|
|
85
85
|
List the facts in the following JSON format:
|
|
86
|
+
|
|
86
87
|
json
|
|
87
88
|
"facts":
|
|
88
89
|
[
|
|
@@ -92,6 +93,7 @@ json
|
|
|
92
93
|
},
|
|
93
94
|
{...}
|
|
94
95
|
]
|
|
96
|
+
|
|
95
97
|
After analyzing the content, classifying its field, and identifying key concepts, and facts, assess whether the discovered elements warrant the creation of testing (quiz) materials.
|
|
96
98
|
|
|
97
99
|
Consider if these elements provide significant educational value to an average learner by enhancing understanding, offering practical applications, or supporting crucial educational goals. If you decide that the source does not hold educational value that is worthy of generating testing material or quizzes for then please provide a reason in less than 90 characters.
|
|
@@ -125,7 +127,6 @@ json
|
|
|
125
127
|
"summary_cards": ["summary_card1_content", "summary_card2_content", "summary_card3_content", "..."]
|
|
126
128
|
}
|
|
127
129
|
|
|
128
|
-
|
|
129
130
|
`;
|
|
130
131
|
|
|
131
132
|
|
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
export class ParseSourceContent{
|
|
2
2
|
public content: any;
|
|
3
|
+
/// Format of Content
|
|
4
|
+
// content: {
|
|
5
|
+
// title: source.title,
|
|
6
|
+
// headings: source.headings,
|
|
7
|
+
// content: source.content,
|
|
8
|
+
// fields: fields,
|
|
9
|
+
// taxonomy: source.source_taxonomy,
|
|
10
|
+
// type: source.source_type
|
|
11
|
+
// },
|
|
12
|
+
|
|
3
13
|
|
|
4
14
|
titles_to_remove = ['See also', 'References', 'Further reading', 'External links', 'Notes and references', 'Bibliography', 'Notes', 'Cited sources'];
|
|
5
15
|
block_types_toremove = ['table','empty_line'];
|
|
@@ -8,9 +18,14 @@ export class ParseSourceContent{
|
|
|
8
18
|
}
|
|
9
19
|
|
|
10
20
|
parseData() {
|
|
11
|
-
|
|
21
|
+
let sourceType = this.content.type;
|
|
22
|
+
let afterSanitized;
|
|
23
|
+
if(sourceType == "video"){
|
|
24
|
+
afterSanitized = this.parseVideoContent(this.content.content);
|
|
25
|
+
}else{
|
|
12
26
|
let dataAfterRemovingUnWantedBlocks = this.removeSectionsByTitle(this.content.content);
|
|
13
|
-
|
|
27
|
+
afterSanitized = this.sanitizeBlocks(dataAfterRemovingUnWantedBlocks);
|
|
28
|
+
}
|
|
14
29
|
return {
|
|
15
30
|
type: this.content.type,
|
|
16
31
|
title: this.content.title,
|
|
@@ -40,7 +55,7 @@ export class ParseSourceContent{
|
|
|
40
55
|
return dataAfterRemoving;
|
|
41
56
|
}
|
|
42
57
|
|
|
43
|
-
|
|
58
|
+
sanitizeTextContent(content: String) {
|
|
44
59
|
// Remove newline characters
|
|
45
60
|
content = content.replace(/\\n/g, ' ');
|
|
46
61
|
|
|
@@ -68,7 +83,7 @@ export class ParseSourceContent{
|
|
|
68
83
|
for (let key in block) {
|
|
69
84
|
let value = block[key];
|
|
70
85
|
if (typeof value === 'string') {
|
|
71
|
-
sanitizedBlock[key] = this.
|
|
86
|
+
sanitizedBlock[key] = this.sanitizeTextContent(value);
|
|
72
87
|
} else if (Array.isArray(value)) {
|
|
73
88
|
sanitizedBlock[key] = this.sanitizeBlocks(value);
|
|
74
89
|
} else {
|
|
@@ -79,6 +94,105 @@ export class ParseSourceContent{
|
|
|
79
94
|
});
|
|
80
95
|
return sanitizedBlocks;
|
|
81
96
|
}
|
|
97
|
+
|
|
98
|
+
parseVideoContent(data: Array<any>){
|
|
99
|
+
let timeCodes :Array<any> = [];
|
|
100
|
+
data.map((e) => timeCodes.push(...e.children));
|
|
101
|
+
let cleanedData = this.cleanTranscript(timeCodes);
|
|
102
|
+
let collapsedData = this.collapseTimeCodes(cleanedData,100);
|
|
103
|
+
return collapsedData;
|
|
104
|
+
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// remove content inside [] which denotes non-speech sounds
|
|
108
|
+
isNonSpeech(content: string) {
|
|
109
|
+
// Check if the content is non-speech (enclosed in square brackets).
|
|
110
|
+
return /^\[.*\]$/.test(content.trim());
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// remove non-essential content
|
|
114
|
+
cleanTranscript(data: Array<any>) {
|
|
115
|
+
// Clean the transcript by removing non-speech content, normalizing whitespace, and keeping only necessary fields.
|
|
116
|
+
const cleanedData = <any>[];
|
|
117
|
+
|
|
118
|
+
data.forEach(entry => {
|
|
119
|
+
let content = (entry.content || '').trim();
|
|
120
|
+
|
|
121
|
+
// Skip non-speech content
|
|
122
|
+
if (this.isNonSpeech(content)) return;
|
|
123
|
+
|
|
124
|
+
// Normalize whitespace in content
|
|
125
|
+
content = content.replace(/\s+/g, ' ');
|
|
126
|
+
|
|
127
|
+
// Only keep start_time, end_time, content
|
|
128
|
+
const currentEntry = {
|
|
129
|
+
start_time: entry.startTime,
|
|
130
|
+
end_time: entry.endTime,
|
|
131
|
+
content: content
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
cleanedData.push(currentEntry);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
return cleanedData;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// collapse the timecode to 30 seconds
|
|
141
|
+
collapseTimeCodes(data: Array<any>, maxDuration = 30.0) {
|
|
142
|
+
// Collapse time codes into buckets of approximately maxDuration seconds.
|
|
143
|
+
const collapsedData = [];
|
|
144
|
+
let bucketStartTime: number | null = null;
|
|
145
|
+
let bucketEndTime : number | null = null;
|
|
146
|
+
let bucketContent : Array<any> = [];
|
|
147
|
+
let bucketDuration = 0.0;
|
|
148
|
+
|
|
149
|
+
data.forEach(entry => {
|
|
150
|
+
const startTime = entry.start_time;
|
|
151
|
+
const endTime = entry.end_time;
|
|
152
|
+
const content = entry.content;
|
|
153
|
+
const entryDuration = endTime - startTime;
|
|
154
|
+
|
|
155
|
+
if (bucketStartTime === null) {
|
|
156
|
+
// Start a new bucket
|
|
157
|
+
bucketStartTime = startTime;
|
|
158
|
+
bucketEndTime = endTime;
|
|
159
|
+
bucketContent.push(content);
|
|
160
|
+
bucketDuration = entryDuration;
|
|
161
|
+
} else if ((bucketDuration + entryDuration) <= maxDuration) {
|
|
162
|
+
// Add to current bucket
|
|
163
|
+
bucketEndTime = endTime;
|
|
164
|
+
bucketContent.push(content);
|
|
165
|
+
bucketDuration += entryDuration;
|
|
166
|
+
} else {
|
|
167
|
+
// Close current bucket and start a new one
|
|
168
|
+
const collapsedEntry = {
|
|
169
|
+
start_time: bucketStartTime,
|
|
170
|
+
end_time: bucketEndTime,
|
|
171
|
+
content: bucketContent.join(' ')
|
|
172
|
+
};
|
|
173
|
+
collapsedData.push(collapsedEntry);
|
|
174
|
+
|
|
175
|
+
// Start new bucket with current entry
|
|
176
|
+
bucketStartTime = startTime;
|
|
177
|
+
bucketEndTime = endTime;
|
|
178
|
+
bucketContent = [content];
|
|
179
|
+
bucketDuration = entryDuration;
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
// Add the last bucket if it exists
|
|
184
|
+
if (bucketContent.length > 0) {
|
|
185
|
+
const collapsedEntry = {
|
|
186
|
+
start_time: bucketStartTime,
|
|
187
|
+
end_time: bucketEndTime,
|
|
188
|
+
content: bucketContent.join(' ')
|
|
189
|
+
};
|
|
190
|
+
collapsedData.push(collapsedEntry);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return collapsedData;
|
|
194
|
+
}
|
|
195
|
+
|
|
82
196
|
|
|
83
197
|
|
|
84
198
|
}
|