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.
@@ -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
- // if(this.cardgenResponse.status_code == 200) {
64
- // this.gapFillResponse = await this._generationForGapFill(this.typologyResponse, this.cardgenResponse);
65
- // responseToReturn.push(this.gapFillResponse);
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 = `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:
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
- "concepts": [
29
- "concept1",
30
- "concept2",
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 must have at least one test card.
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": "source_title#main_heading"
84
+ "reference": "main_heading"
90
85
  },
91
86
  {
92
87
  "concept_text": "concept2_content",
93
- "reference": "source_title#main_heading"
88
+ "reference": "main_heading"
94
89
  },
95
90
  {...}
96
91
  ],
97
92
  "facts":
98
93
  [
99
94
  {
100
- "factt_text": "fact1_content",
101
- "reference": "source_title#main_heading"
95
+ "fact_text": "fact1_content",
96
+ "reference": "main_heading"
102
97
  },
103
98
  {
104
99
  "fact_text": "fact2_content",
105
- "reference": "source_title#main_heading"
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": "source_title#main_heading"
133
+ "reference": "main_heading"
139
134
  },
140
135
  {
141
136
  "concept_text": "concept2_content",
142
- "reference": "source_title#main_heading"
137
+ "reference": "main_heading"
143
138
  },
144
139
  {...}
145
140
  ],
146
141
  "facts":
147
142
  [
148
143
  {
149
- "factt_text": "fact1_content",
150
- "reference": "source_title#main_heading"
144
+ "fact_text": "fact1_content",
145
+ "reference": "main_heading"
151
146
  },
152
147
  {
153
148
  "fact_text": "fact2_content",
154
- "reference": "source_title#main_heading"
149
+ "reference": "main_heading"
155
150
  },
156
151
  {...}
157
152
  ],
158
153
  "bloom_level": <1-5>
159
154
  }
160
155
 
161
- Minimum choices required: 2
162
- Maximum choices allowed: 8
163
- Minimum correct choices required: 1
164
- Maximum character length for the prompt: 320
165
- Maximum character length for an individual cloze: 90
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
- "card_content": [
173
- {
174
- "left_item": "left choice",
175
- "right_item": [right item]
176
- },
177
- {
178
- "left_item":" left choice",
179
- "right_item": [right item]
180
- },
181
- {
182
- "left_item": "left choice",
183
- "right_item": [right item]
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": "source_title#main_heading"
183
+ "reference": "main_heading"
192
184
  },
193
185
  {
194
186
  "concept_text": "concept2_content",
195
- "reference": "source_title#main_heading"
187
+ "reference": "main_heading"
196
188
  },
197
189
  {...}
198
190
  ],
199
191
  "facts":
200
192
  [
201
193
  {
202
- "factt_text": "fact1_content",
203
- "reference": "source_title#main_heading"
194
+ "fact_text": "fact1_content",
195
+ "reference": "main_heading"
204
196
  },
205
197
  {
206
198
  "fact_text": "fact2_content",
207
- "reference": "source_title#main_heading"
199
+ "reference": "main_heading"
208
200
  },
209
201
  {...}
210
202
  ],
211
203
  "bloom_level": <1-5>
212
204
  }
213
205
 
214
- Maximum character length for each item in a pair: 42
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
- 1. Ensure that you produce at least one if not more card for each concept and fact.
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. The reference indicates the part of the text that is most relevant for that particular concept. Whenever possible, pick a main heading to direct the user to the most relevant part of the source material. The reference schema is as follows: source_title#main_heading, where #main_heading is optional. If a concept needs to reference multiple sections or the entire source then simply leave the reference as empty.
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. The reference indicates the part of the text that is most relevant for that particular concept. Whenever possible, pick a main heading to direct the user to the most relevant part of the source material. The reference schema is as follows: source_title#main_heading, where #main_heading is optional. If a fact needs to reference multiple sections or the entire source then simply leave the reference as empty.
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
- // if(this.content.type == 'source') {
12
- let dataAfterRemovingUnWantedBlocks = this.removeSectionsByTitle(this.content.content);
13
- let afterSanitized = this.sanitizeBlocks(dataAfterRemovingUnWantedBlocks);
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
- sanitizeWikiContent(content) {
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.sanitizeWikiContent(value);
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "only_ever_generator",
3
- "version": "0.4.6",
3
+ "version": "0.4.8",
4
4
  "main": "dist/index.js",
5
5
  "scripts": {
6
6
  "start": "npm run build && nodemon dist/index.js",
@@ -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
- // if(this.cardgenResponse.status_code == 200) {
82
- // this.gapFillResponse = await this._generationForGapFill(this.typologyResponse, this.cardgenResponse);
83
- // responseToReturn.push(this.gapFillResponse);
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
- "Exclude generating cards with content in the following",
114
- JSON.stringify(cardGenData.cards_data),
114
+ JSON.stringify(gapFill) ,
115
+
116
+ "",
115
117
  true
116
118
  );
117
119
  }
@@ -1,4 +1,5 @@
1
- const promptString: string = `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:
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
- "concepts": [
26
- "concept1",
27
- "concept2",
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 must have at least one test card.
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": "source_title#main_heading"
81
+ "reference": "main_heading"
87
82
  },
88
83
  {
89
84
  "concept_text": "concept2_content",
90
- "reference": "source_title#main_heading"
85
+ "reference": "main_heading"
91
86
  },
92
87
  {...}
93
88
  ],
94
89
  "facts":
95
90
  [
96
91
  {
97
- "factt_text": "fact1_content",
98
- "reference": "source_title#main_heading"
92
+ "fact_text": "fact1_content",
93
+ "reference": "main_heading"
99
94
  },
100
95
  {
101
96
  "fact_text": "fact2_content",
102
- "reference": "source_title#main_heading"
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": "source_title#main_heading"
130
+ "reference": "main_heading"
136
131
  },
137
132
  {
138
133
  "concept_text": "concept2_content",
139
- "reference": "source_title#main_heading"
134
+ "reference": "main_heading"
140
135
  },
141
136
  {...}
142
137
  ],
143
138
  "facts":
144
139
  [
145
140
  {
146
- "factt_text": "fact1_content",
147
- "reference": "source_title#main_heading"
141
+ "fact_text": "fact1_content",
142
+ "reference": "main_heading"
148
143
  },
149
144
  {
150
145
  "fact_text": "fact2_content",
151
- "reference": "source_title#main_heading"
146
+ "reference": "main_heading"
152
147
  },
153
148
  {...}
154
149
  ],
155
150
  "bloom_level": <1-5>
156
151
  }
157
152
 
158
- Minimum choices required: 2
159
- Maximum choices allowed: 8
160
- Minimum correct choices required: 1
161
- Maximum character length for the prompt: 320
162
- Maximum character length for an individual cloze: 90
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
- "card_content": [
170
- {
171
- "left_item": "left choice",
172
- "right_item": [right item]
173
- },
174
- {
175
- "left_item":" left choice",
176
- "right_item": [right item]
177
- },
178
- {
179
- "left_item": "left choice",
180
- "right_item": [right item]
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": "source_title#main_heading"
180
+ "reference": "main_heading"
189
181
  },
190
182
  {
191
183
  "concept_text": "concept2_content",
192
- "reference": "source_title#main_heading"
184
+ "reference": "main_heading"
193
185
  },
194
186
  {...}
195
187
  ],
196
188
  "facts":
197
189
  [
198
190
  {
199
- "factt_text": "fact1_content",
200
- "reference": "source_title#main_heading"
191
+ "fact_text": "fact1_content",
192
+ "reference": "main_heading"
201
193
  },
202
194
  {
203
195
  "fact_text": "fact2_content",
204
- "reference": "source_title#main_heading"
196
+ "reference": "main_heading"
205
197
  },
206
198
  {...}
207
199
  ],
208
200
  "bloom_level": <1-5>
209
201
  }
210
202
 
211
- Maximum character length for each item in a pair: 42
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
- 1. Ensure that you produce at least one if not more card for each concept and fact.
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. The reference indicates the part of the text that is most relevant for that particular concept. Whenever possible, pick a main heading to direct the user to the most relevant part of the source material. The reference schema is as follows: source_title#main_heading, where #main_heading is optional. If a concept needs to reference multiple sections or the entire source then simply leave the reference as empty.
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. The reference indicates the part of the text that is most relevant for that particular concept. Whenever possible, pick a main heading to direct the user to the most relevant part of the source material. The reference schema is as follows: source_title#main_heading, where #main_heading is optional. If a fact needs to reference multiple sections or the entire source then simply leave the reference as empty.
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
- // if(this.content.type == 'source') {
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
- let afterSanitized = this.sanitizeBlocks(dataAfterRemovingUnWantedBlocks);
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
- sanitizeWikiContent(content: String) {
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.sanitizeWikiContent(value);
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
  }