only_ever_generator 0.0.8 → 0.1.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.
@@ -18,51 +18,66 @@ const typology_prompt_1 = require("../constants/prompts/typology_prompt");
18
18
  const generate_typology_1 = require("../typology_gen/generate_typology");
19
19
  const generate_args_1 = require("../utils/generate_args");
20
20
  const source_data_1 = require("../constants/source_data");
21
- /// OnlyEverGenerator
21
+ function isEmpty(obj) {
22
+ return Object.keys(obj).length === 0;
23
+ }
24
+ /// OnlyEverGenerator
22
25
  class OnlyEverGenerator {
23
26
  constructor(apiKey, model, content, expected_fields) {
24
- this.api_key = '';
25
- this.parsedContent = '';
27
+ this.api_key = "";
28
+ this.parsedContent = "";
26
29
  this.typologyResponse = {};
27
30
  this.cardgenResponse = {};
28
31
  this.summarizeResponse = {};
32
+ this.gapFillResponse = {};
29
33
  this.api_key = apiKey;
30
- this.openAiService = new open_ai_service_1.OpenAiService(apiKey, model !== null && model !== void 0 ? model : 'gpt-3.5-turbo-1106');
34
+ this.openAiService = new open_ai_service_1.OpenAiService(apiKey, model !== null && model !== void 0 ? model : "gpt-3.5-turbo-1106");
31
35
  this.parsedContent = new parse_source_content_1.ParseSourceContent(content).parse();
32
36
  this.expectedFields = (0, source_data_1.returnFields)();
33
37
  }
34
- ;
35
38
  generate() {
36
39
  return __awaiter(this, arguments, void 0, function* (generate_typology = false, generate_card = false) {
37
- var _a, _b;
40
+ var _a, _b, _c;
38
41
  let typologyPrompt = (0, typology_prompt_1.returnTypologyPrompt)();
39
42
  let cardPrompt = (0, card_gen_prompt_1.returnCardGenPrompt)();
40
43
  let args = new generate_args_1.GenerateArgs(generate_card, generate_typology, false, {
41
44
  typology_prompt: typologyPrompt,
42
45
  card_gen_prompt: cardPrompt,
43
- summary_prompt: ''
46
+ summary_prompt: "",
44
47
  });
45
48
  const responseToReturn = [];
46
49
  const whatNeedsToBeGenerated = args.getWhatNeedsToBeGenerated();
47
50
  for (let elem of whatNeedsToBeGenerated)
48
- if (elem == 'generate_tyopology') {
49
- this.typologyResponse = yield this.generateTypology((_a = args.prompts.typology_prompt) !== null && _a !== void 0 ? _a : '');
51
+ if (elem == "generate_tyopology") {
52
+ this.typologyResponse = yield this.generateTypology((_a = args.prompts.typology_prompt) !== null && _a !== void 0 ? _a : "");
50
53
  responseToReturn.push(this.typologyResponse);
51
54
  }
52
- else if (elem == 'generate_card') {
53
- this.cardgenResponse = yield this.generateCard((_b = args.prompts.card_gen_prompt) !== null && _b !== void 0 ? _b : '', this.parsedContent + JSON.stringify(this.typologyResponse));
55
+ else if (elem == "generate_card") {
56
+ this.cardgenResponse = yield this.generateCard((_b = args.prompts.card_gen_prompt) !== null && _b !== void 0 ? _b : "", this.parsedContent + JSON.stringify(this.typologyResponse), false);
54
57
  responseToReturn.push(this.cardgenResponse);
55
58
  }
59
+ if (this.cardgenResponse.status_code == 200) {
60
+ let gapFill = this.gapFilling();
61
+ if (gapFill.remainingConcepts.length !== 0 ||
62
+ gapFill.remainingFacts.length !== 0) {
63
+ this.gapFillResponse = yield this.generateCard((_c = args.prompts.card_gen_prompt) !== null && _c !== void 0 ? _c : "", this.parsedContent +
64
+ "Generate cards only suitable for the given remaining concepts and facts" +
65
+ JSON.stringify(gapFill) +
66
+ "Exclude generating these cards" +
67
+ JSON.stringify(this.cardgenResponse.cards_data), true);
68
+ }
69
+ responseToReturn.push(this.gapFillResponse);
70
+ }
56
71
  return responseToReturn;
57
72
  });
58
73
  }
59
74
  _returnParsedContent() {
60
75
  return this.parsedContent;
61
76
  }
62
- generateCard(prompt, content) {
77
+ generateCard(prompt, content, isGapFill) {
63
78
  return __awaiter(this, void 0, void 0, function* () {
64
79
  let generateCards = new generate_cards_1.GenerateCards(this.openAiService);
65
- let cardgenResponse = yield generateCards.generateCards(prompt !== null && prompt !== void 0 ? prompt : '', content);
80
+ let cardgenResponse = yield generateCards.generateCards(prompt !== null && prompt !== void 0 ? prompt : "", content, isGapFill);
66
81
  // let response = await this.openAiService?.sendRequest(prompt,this.parsedContent);
67
82
  // response['type'] = 'card_gen';
68
83
  return cardgenResponse;
@@ -74,5 +89,40 @@ class OnlyEverGenerator {
74
89
  return response;
75
90
  });
76
91
  }
92
+ gapFilling() {
93
+ var _a, _b, _c, _d, _e;
94
+ let allConcepts = [];
95
+ let allFacts = [];
96
+ let generatedConceptsList = [];
97
+ let generatedFactsList = [];
98
+ if (!isEmpty(this.typologyResponse)) {
99
+ allConcepts.push(...((_a = this.typologyResponse.concepts) !== null && _a !== void 0 ? _a : []));
100
+ allFacts.push(...((_c = (_b = this.typologyResponse) === null || _b === void 0 ? void 0 : _b.facts) !== null && _c !== void 0 ? _c : []));
101
+ }
102
+ if (!isEmpty(this.cardgenResponse)) {
103
+ allConcepts.push(...((_d = this.cardgenResponse.missing_concepts) !== null && _d !== void 0 ? _d : []));
104
+ allFacts.push(...((_e = this.cardgenResponse.missing_facts) !== null && _e !== void 0 ? _e : []));
105
+ }
106
+ for (let card of this.cardgenResponse.cards_data) {
107
+ if (card.concepts.length != 0) {
108
+ generatedConceptsList.push(...card.concepts);
109
+ }
110
+ if (card.facts.length != 0) {
111
+ generatedFactsList.push(...card.facts);
112
+ }
113
+ }
114
+ let generatedConceptsSet = Array.from(new Set(generatedConceptsList));
115
+ let generatedFactsSet = Array.from(new Set(generatedFactsList));
116
+ let remainingConcepts = allConcepts.filter((item) => !generatedConceptsSet.includes(item));
117
+ let remainingFacts = allFacts.filter((item) => !generatedFactsSet.includes(item));
118
+ return {
119
+ // allConcepts: allConcepts,
120
+ // allFacts: allFacts,
121
+ // generatedConcepts: generatedConceptsSet,
122
+ // generatedFacts: generatedFactsSet,
123
+ remainingConcepts: remainingConcepts,
124
+ remainingFacts: remainingFacts,
125
+ };
126
+ }
77
127
  }
78
128
  exports.OnlyEverGenerator = OnlyEverGenerator;
@@ -14,12 +14,12 @@ class GenerateCards {
14
14
  constructor(openAiService) {
15
15
  this.openAiService = openAiService;
16
16
  }
17
- generateCards(prompt, parsedContent) {
17
+ generateCards(prompt, parsedContent, isGapFill) {
18
18
  return __awaiter(this, void 0, void 0, function* () {
19
19
  var _a, _b, _c;
20
20
  let response = yield ((_a = this.openAiService) === null || _a === void 0 ? void 0 : _a.sendRequest(prompt, parsedContent));
21
- console.log("response to card generation ", response);
22
- response["type"] = "card_gen";
21
+ // console.log("response to card generation ", response);
22
+ response["type"] = isGapFill ? "gap_fill" : "card_gen";
23
23
  response.metadata = {
24
24
  "req_time": response.generated_at,
25
25
  "req_type": response.type,
@@ -42,25 +42,28 @@ class GenerateCards {
42
42
  const missing_concepts = generatedData.generated_content.missing_concepts;
43
43
  const missing_facts = generatedData.generated_content.missing_facts;
44
44
  const unparsedTestCards = generatedData.generated_content.test_cards;
45
- for (let elem of unparsedTestCards) {
46
- if (elem.type == "flash") {
47
- cardData.push(this.parseFlashCard(elem));
48
- }
49
- else if (elem.type == "mcq") {
50
- cardData.push(this.parseMcqCard(elem));
51
- }
52
- else if (elem.type == "cloze") {
53
- cardData.push(this.parseClozeCard(elem));
54
- }
55
- else if (elem.type == "match") {
56
- cardData.push(this.parseMatchCard(elem));
45
+ const type = generatedData.type;
46
+ if (unparsedTestCards !== undefined && unparsedTestCards.length != 0) {
47
+ for (let elem of unparsedTestCards) {
48
+ if (elem.type == "flash") {
49
+ cardData.push(this.parseFlashCard(elem));
50
+ }
51
+ else if (elem.type == "mcq") {
52
+ cardData.push(this.parseMcqCard(elem));
53
+ }
54
+ else if (elem.type == "cloze") {
55
+ cardData.push(this.parseClozeCard(elem));
56
+ }
57
+ else if (elem.type == "match") {
58
+ cardData.push(this.parseMatchCard(elem));
59
+ }
57
60
  }
58
61
  }
59
62
  usage_data["created_at"] = created_at;
60
- usage_data["type"] = "card_gen";
61
63
  return {
62
64
  status_code: status_code,
63
65
  metadata: usage_data,
66
+ type: type,
64
67
  missing_concepts: missing_concepts,
65
68
  missing_facts: missing_facts,
66
69
  cards_data: cardData,
@@ -27,7 +27,7 @@ json
27
27
  {
28
28
  "type": "flash" | "mcq" | "cloze" | "match",
29
29
  "card_content": { "front": "...", "back": "..." | "prompt": "...", "choices": [ ... ] | "prompt": "...", "options": [ ... ] | "right_choice 1": "...", "left_choice 1": "..." },
30
- "card_reference": "source_title#heading",
30
+ "card_reference": "heading",
31
31
  "concepts": ["Concept1", "Concept2", "..."],
32
32
  "facts": ["Fact1", "Fact2", "..."]
33
33
  }
@@ -35,11 +35,10 @@ json
35
35
 
36
36
  **Criteria**
37
37
  • Each test card must include at least one concept or fact.
38
- Deprioritize the Flashcards, must not exceed 15% of the total number of cards.
38
+ • Flashcards must not exceed 15% of the total number of cards.
39
39
  • Each concept and fact must have at least one test card.
40
40
 
41
41
  Further instructions are provided below.
42
-
43
42
  Concepts are fundamental ideas that form the basis of knowledge in any discipline. They help organize and explain information, making it accessible and relatable.
44
43
 
45
44
  You are provided with a list of identified concepts. Review this list and the content to determine if any concepts are missing.
@@ -67,7 +66,7 @@ json
67
66
  {
68
67
  "missing_facts": ["fact1", "fact2", "fact3", "..."]
69
68
  }
70
- After you have the complete list of concepts and facts, including any missing ones you identified, proceed to generate test cards for each.
69
+ After you have the complete list of concepts and facts, including any missing ones you identified, proceed to generate test cards for each.
71
70
 
72
71
  1. Clarity: Ensure the test content is clear and unambiguous.
73
72
  2. Specificity: Be specific about what you are asking. Avoid vague or overly broad questions or prompts.
@@ -77,23 +76,29 @@ json
77
76
  Test cards must be one of the following types:
78
77
 
79
78
  1. Flashcards: Have a front and back.
79
+ 2. A flashcard consists of two sides: a front and a back. Both the front and back text content must not exceed more than 300 characters in length.
80
80
 
81
- json
81
+ json schema for Flash Cards:
82
82
  {
83
83
  "type": "flash",
84
84
  "card_content": {
85
- "front": "<content for the front>",
86
- "back": "<content for the back>"
85
+ "front": "<content for the front of the flashcard>",
86
+ "back": "<content for the back of the flashcard>"
87
87
  },
88
- "card_reference": "source_title#heading",
88
+ "card_reference": "heading",
89
89
  "concepts": ["Concept1", "Concept2", "..."],
90
90
  "facts": ["Fact1", "Fact2", "..."]
91
91
  }
92
92
 
93
- - Each side must not exceed 300 characters.
93
+
94
94
  2. Multiple Choice Questions (MCQ): Provide multiple choices to pick from. One or more should be correct.
95
+ • Minimum choices required: 2
96
+ • Maximum choices allowed: 8
97
+ • Minimum correct choices required: 1
98
+ • Maximum character length for the prompt: 320
99
+ • Maximum character length for each choice: 42
95
100
 
96
- json
101
+ json schema for mcqs
97
102
  {
98
103
  "type": "mcq",
99
104
  "card_content": {
@@ -104,156 +109,55 @@ json
104
109
  "... up to 8 choices"
105
110
  ]
106
111
  },
107
- "card_reference": "source_title#heading",
112
+ "card_reference": "heading",
108
113
  "concepts": ["Concept1", "Concept2", "..."],
109
114
  "facts": ["Fact1", "Fact2", "..."]
110
115
  }
111
116
 
117
+ 3. Cloze:
118
+ Fill-in-the-blank style test card. Use double curly braces {{}} to indicate a cloze this is absolute necessagr
112
119
  • Minimum choices required: 2
113
120
  • Maximum choices allowed: 8
114
121
  • Minimum correct choices required: 1
115
122
  • Maximum character length for the prompt: 320
116
- • Maximum character length for each choice: 42
117
-
118
- 3. Cloze: Fill-in-the-blank style test card. Use double curly braces {{}} to indicate a cloze.
123
+ • Maximum character length for an individual cloze: 90
119
124
 
120
- json
125
+ json schema for cloze
121
126
  {
122
127
  "type": "cloze",
123
- "card_content":{
124
- "text": "<clozed_text>",
125
- "options": [
126
- {"option" : "<cloze_0>", "cloze" : "<position_0>"},
127
- {"option" : "<cloze_1>", "cloze" : "<position_1>,
128
- {"option" : "<cloze_2>", "cloze" : "<position_2>"},
129
- ....
130
- {"option" : "<cloze_6>", "cloze" : "<position_6>"},
128
+ "card_content": {
129
+ "text": "Accidentals in music denote {{c0:notes}} that do not belong to the {{c1:scale}} or {{c2:mode}} indicated by the key signature.",
130
+ "options": [
131
+ {"option": "notes", "cloze": "c0"},
132
+ {"option": "scale", "cloze": "c1"},
133
+ {"option": "mode", "cloze": "c2"},
134
+ {"option": "chords", "cloze": null},
135
+ "... up to 8 choices"
131
136
  ]
132
-
133
- }
134
- "card_reference": "source_title#heading",
137
+ },
138
+ "card_reference": "heading",
135
139
  "concepts": ["Concept1", "Concept2", "..."],
136
140
  "facts": ["Fact1", "Fact2", "..."]
137
141
  }
138
142
 
139
- • Minimum choices required: 2
140
- • Maximum choices allowed: 8
141
- • Minimum correct choices required: 1
142
- • Maximum character length for the prompt: 320
143
- • Maximum character length for an individual cloze: 90
143
+
144
144
 
145
145
  4. Match: Pairing items.
146
+ • Maximum character length for each item in a pair: 42
146
147
 
147
- json
148
+ json schema for match
148
149
  {
149
150
  "type": "match",
150
151
  "card_content": {
151
- "<left_text1>": "<right_text1>",
152
- "<left_text2>": "<right_text2>",
153
- "<left_text3>": "<right_text3>",
154
- ...
155
- "<left_text8>": "<right_text8>"
156
- }
157
- "card_reference": "source_title#heading",
152
+ "right_choice 1": "left_choice 1",
153
+ "right_choice 2": "left_choice 2",
154
+ "... up to 8 total pairs"
155
+ },
156
+ "card_reference": "heading",
158
157
  "concepts": ["Concept1", "Concept2", "..."],
159
158
  "facts": ["Fact1", "Fact2", "..."]
160
159
  }
161
160
 
162
- • Maximum character length for each item in a pair: 42
163
-
164
-
165
- The schema for each card type is below.
166
-
167
- A flashcard consists of two sides: a front and a back. Both the front and back text content must not exceed more than 300 characters in length.
168
-
169
- The content schema should be represented in this manner:
170
- json
171
- {
172
- "front": "<content for the front of the flashcard>",
173
- "back": "<content for the back of the flashcard>"
174
- }
175
-
176
-
177
- The schema for an mcq card is shown below.
178
-
179
- json
180
- {
181
- "prompt": "<question text>",
182
- "choices":
183
- [
184
- {
185
- choice: "choice 1",
186
- is_correct: true or false
187
- },
188
- {
189
- choice: "choice 2",
190
- is_correct: true or false
191
- }
192
- "... up to 8 choices"
193
- ]
194
- }
195
-
196
- Minimum choices required: 2
197
- Maximum choices allowed: 8
198
- Minimum correct choices required: 1
199
- Maximum character length for the prompt: 320
200
- Maximum character length for each choice: 42
201
-
202
-
203
- For questions of the "type": "cloze", which refers to a fill-in-the-blank style question, the format is outlined below. I have used the sample text here because it is easier to illustrate the schema with an example:
204
-
205
- json
206
- {
207
- "prompt": "Accidentals in music denote {{c0:notes}} that do not belong to the {{c1:scale}} or {{c2:mode}} indicated by the key signature."
208
- "options":
209
- [
210
- {
211
- "option: "notes",
212
- "cloze": "c0"
213
- },
214
- {
215
- "option: "chords",
216
- "cloze": null
217
- },
218
- {
219
- "option: "scale",
220
- "cloze": "c1"
221
- },
222
- {
223
- "option: "mode",
224
- "cloze": "c2"
225
- },
226
-
227
- {
228
- "option: "tilda",
229
- "cloze": null
230
- },
231
- {
232
- "option: "score",
233
- "cloze": null
234
- },
235
- "... up to a maximum of 8 choices total"
236
- ]
237
- }
238
-
239
- Minimum choices required: 2
240
- Maximum choices allowed: 8
241
- Minimum correct choices required: 1
242
- Maximum character length for the prompt: 320
243
- Maximum character length for an individual cloze: 90
244
-
245
- The schema for match type cards are as follows.
246
- json
247
- {
248
- "<left_text1>": "<right_text1>",
249
- "<left_text2>": "<right_text2>",
250
- "<left_text3>": "<right_text3>",
251
- ...
252
- "<left_text8>": "<right_text8>"
253
- }
254
-
255
- Maximum character length for each item in a pair: 42
256
- Each test card needs 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 reference schema is as follows: source_title#main_heading, where #main_heading is optional.
257
161
  Once you are done generating the test cards. Go back and evaulate the full list of concepts and fact that include any of the missing concepts or facts along with the list that was provided as the input.
258
162
 
259
163
  Are there any concept or fact that don't have a test card yet? If yes, go back and create one.
@@ -267,7 +171,6 @@ Once you are done generating the test cards, review the full list of concepts an
267
171
  3. Repeat this step until all concepts and facts are covered.
268
172
 
269
173
  Only stop generating test questions once you believe there is sufficient testing material for learners to fully understand the concepts and remember the facts. The same concept or fact can have multiple test cards, so continue creating test cards until you are confident that there are enough for learners to fully grasp the source material.
270
-
271
174
  `;
272
175
  function returnCardGenPrompt() {
273
176
  return promptString;
package/dist/index.js CHANGED
@@ -1,11 +1,14 @@
1
1
  "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.OnlyEverGenerator = void 0;
4
2
  // import express from "express";
5
3
  // import { returnCardGenPrompt } from "./constants/prompts/card_gen_prompt";
6
4
  // import { returnTypologyPrompt } from "./constants/prompts/typology_prompt";
7
5
  // import { GenerateArgs } from "./utils/generate_args";
8
6
  // import { returnFields, returnHeadings, returnSourceData } from "./constants/source_data";
7
+ // import config from "./config";
8
+ // const app = express();
9
+ // const port = 3000;
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.OnlyEverGenerator = void 0;
9
12
  const app_1 = require("./bootstrap/app");
10
13
  Object.defineProperty(exports, "OnlyEverGenerator", { enumerable: true, get: function () { return app_1.OnlyEverGenerator; } });
11
14
  /// All the Codes Below uses express and are strictly for development purpose, while publishing the package, comment everything
@@ -22,7 +25,7 @@ Object.defineProperty(exports, "OnlyEverGenerator", { enumerable: true, get: fun
22
25
  // let content = returnSourceData().toString()
23
26
  // let headings = returnHeadings();
24
27
  // // let aiRequest = await openAIRequest(prompt,content);
25
- // let aiRequest = await oeGen.generateCard(prompt,content);
28
+ // let aiRequest = await oeGen.generateCard(prompt,content, false);
26
29
  // res.send(aiRequest);
27
30
  // });
28
31
  // app.get('/typology', async(req,res)=>{
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "only_ever_generator",
3
- "version": "0.0.8",
3
+ "version": "0.1.0",
4
4
  "main": "dist/index.js",
5
5
  "scripts": {
6
- "start": "nodemon dist/index.js",
6
+ "start": "npm run build && nodemon dist/index.js",
7
7
  "build": "tsc",
8
8
  "test": "echo \"Error: no test specified\" && exit 1"
9
9
  },
@@ -21,6 +21,7 @@
21
21
  "axios": "^1.7.2",
22
22
  "dotenv": "^16.4.5",
23
23
  "express": "^4.19.2"
24
+
24
25
  },
25
26
  "eslintConfig": {
26
27
  "parser": "typescript-eslint-parser",
@@ -8,81 +8,152 @@ import { GenerateArgs } from "../utils/generate_args";
8
8
  import { returnFields } from "../constants/source_data";
9
9
  import { returnTypologyData } from "../parse/response_format_typology";
10
10
 
11
+ function isEmpty(obj: object): boolean {
12
+ return Object.keys(obj).length === 0;
13
+ }
14
+ /// OnlyEverGenerator
11
15
 
12
- /// OnlyEverGenerator
16
+ export class OnlyEverGenerator {
17
+ public api_key: string = "";
18
+ public openAiService: OpenAiService;
19
+ parsedContent: string = "";
20
+ expectedFields: Array<string>;
21
+ constructor(
22
+ apiKey: string,
23
+ model: string,
24
+ content: Array<any>,
25
+ expected_fields: Array<string>
26
+ ) {
27
+ this.api_key = apiKey;
28
+ this.openAiService = new OpenAiService(
29
+ apiKey,
30
+ model ?? "gpt-3.5-turbo-1106"
31
+ );
32
+ this.parsedContent = new ParseSourceContent(content).parse();
33
+ this.expectedFields = returnFields();
34
+ }
13
35
 
14
- export class OnlyEverGenerator{
15
- public api_key: string = '';
16
- public openAiService: OpenAiService;
17
- parsedContent: string = '';
18
- expectedFields: Array<string>
19
- constructor(apiKey:string, model: string, content: Array<any>, expected_fields: Array<string>){
20
- this.api_key = apiKey;
21
- this.openAiService = new OpenAiService(apiKey,model ?? 'gpt-3.5-turbo-1106');
22
- this.parsedContent = new ParseSourceContent(content).parse();
23
- this.expectedFields = returnFields()
24
- };
36
+ typologyResponse: any = {};
37
+ cardgenResponse: any = {};
38
+ summarizeResponse = {};
39
+ gapFillResponse: any = {};
25
40
 
26
- typologyResponse = {};
27
- cardgenResponse = {};
28
- summarizeResponse = {};
41
+ async generate(
42
+ generate_typology: boolean = false,
43
+ generate_card: boolean = false
44
+ ): Promise<Array<any>> {
45
+ let typologyPrompt = returnTypologyPrompt();
46
+ let cardPrompt = returnCardGenPrompt();
47
+ let args = new GenerateArgs(generate_card, generate_typology, false, {
48
+ typology_prompt: typologyPrompt,
49
+ card_gen_prompt: cardPrompt,
50
+ summary_prompt: "",
51
+ });
52
+ const responseToReturn = [];
53
+ const whatNeedsToBeGenerated = args.getWhatNeedsToBeGenerated();
54
+ for (let elem of whatNeedsToBeGenerated)
55
+ if (elem == "generate_tyopology") {
56
+ this.typologyResponse = await this.generateTypology(
57
+ args.prompts.typology_prompt ?? ""
58
+ );
59
+ responseToReturn.push(this.typologyResponse);
60
+ } else if (elem == "generate_card") {
61
+ this.cardgenResponse = await this.generateCard(
62
+ args.prompts.card_gen_prompt ?? "",
63
+ this.parsedContent + JSON.stringify(this.typologyResponse),
64
+ false
65
+ );
66
+ responseToReturn.push(this.cardgenResponse);
67
+ }
68
+ if (this.cardgenResponse.status_code == 200) {
69
+ let gapFill = this.gapFilling();
70
+ if (
71
+ gapFill.remainingConcepts.length !== 0 ||
72
+ gapFill.remainingFacts.length !== 0
73
+ ) {
74
+ this.gapFillResponse = await this.generateCard(
75
+ args.prompts.card_gen_prompt ?? "",
76
+ this.parsedContent +
77
+ "Generate cards only suitable for the given remaining concepts and facts" +
78
+ JSON.stringify(gapFill) +
79
+ "Exclude generating these cards" +
80
+ JSON.stringify(this.cardgenResponse.cards_data),
81
+ true
82
+ );
83
+ }
84
+ responseToReturn.push(this.gapFillResponse);
85
+ }
29
86
 
30
-
31
-
87
+ return responseToReturn;
88
+ }
32
89
 
33
- async generate(
34
- generate_typology: boolean =false,
35
- generate_card : boolean = false,
36
- ): Promise<Array<any>> {
37
- let typologyPrompt = returnTypologyPrompt();
38
- let cardPrompt = returnCardGenPrompt();
39
- let args = new GenerateArgs(
40
- generate_card,
41
- generate_typology,
42
- false,
43
- {
44
- typology_prompt: typologyPrompt,
45
- card_gen_prompt: cardPrompt,
46
- summary_prompt: ''
47
- },
48
-
49
- );
50
- const responseToReturn = [];
51
- const whatNeedsToBeGenerated = args.getWhatNeedsToBeGenerated();
52
- for(let elem of whatNeedsToBeGenerated)
53
- if(elem == 'generate_tyopology'){
54
- this.typologyResponse = await this.generateTypology(args.prompts.typology_prompt ?? '');
55
- responseToReturn.push(this.typologyResponse);
56
- }else if(elem == 'generate_card'){
57
- this.cardgenResponse = await this.generateCard(args.prompts.card_gen_prompt ?? '', this.parsedContent + JSON.stringify(this.typologyResponse));
58
- responseToReturn.push(this.cardgenResponse);
59
- }
90
+ _returnParsedContent() {
91
+ return this.parsedContent;
92
+ }
60
93
 
61
- return responseToReturn;
62
-
63
- }
64
-
65
- _returnParsedContent(){
66
- return this.parsedContent;
67
- }
94
+ async generateCard(prompt: string, content: string, isGapFill: boolean) {
95
+ let generateCards = new GenerateCards(this.openAiService);
96
+ let cardgenResponse = await generateCards.generateCards(
97
+ prompt ?? "",
98
+ content,
99
+ isGapFill
100
+ );
101
+ // let response = await this.openAiService?.sendRequest(prompt,this.parsedContent);
102
+ // response['type'] = 'card_gen';
103
+ return cardgenResponse;
104
+ }
105
+
106
+ async generateTypology(prompt: string) {
107
+ let response = await new GenerateTypology(
108
+ this.openAiService,
109
+ prompt,
110
+ this.parsedContent,
111
+ this.expectedFields
112
+ ).generate();
113
+ return response;
114
+ }
68
115
 
116
+ gapFilling() {
117
+ let allConcepts: string[] = [];
118
+ let allFacts: string[] = [];
119
+ let generatedConceptsList: string[] = [];
120
+ let generatedFactsList: string[] = [];
121
+ if (!isEmpty(this.typologyResponse)) {
122
+ allConcepts.push(...(this.typologyResponse.concepts ?? []));
123
+ allFacts.push(...(this.typologyResponse?.facts ?? []));
124
+ }
69
125
 
70
- async generateCard(prompt: string, content: string){
71
- let generateCards = new GenerateCards(this.openAiService);
72
- let cardgenResponse = await generateCards.generateCards(prompt ?? '', content);
73
- // let response = await this.openAiService?.sendRequest(prompt,this.parsedContent);
74
- // response['type'] = 'card_gen';
75
- return cardgenResponse;
126
+ if (!isEmpty(this.cardgenResponse)) {
127
+ allConcepts.push(...(this.cardgenResponse.missing_concepts ?? []));
128
+ allFacts.push(...(this.cardgenResponse.missing_facts ?? []));
76
129
  }
77
130
 
78
- async generateTypology(prompt:string){
79
- let response = await new GenerateTypology(
80
- this.openAiService,
81
- prompt,
82
- this.parsedContent,
83
- this.expectedFields,
84
- ).generate();
85
- return response;
131
+ for (let card of this.cardgenResponse.cards_data) {
132
+ if (card.concepts.length != 0) {
133
+ generatedConceptsList.push(...card.concepts);
134
+ }
135
+ if (card.facts.length != 0) {
136
+ generatedFactsList.push(...card.facts);
137
+ }
86
138
  }
87
-
88
- }
139
+
140
+ let generatedConceptsSet = Array.from(new Set(generatedConceptsList));
141
+ let generatedFactsSet = Array.from(new Set(generatedFactsList));
142
+
143
+ let remainingConcepts: string[] = allConcepts.filter(
144
+ (item) => !generatedConceptsSet.includes(item)
145
+ );
146
+ let remainingFacts: string[] = allFacts.filter(
147
+ (item) => !generatedFactsSet.includes(item)
148
+ );
149
+
150
+ return {
151
+ // allConcepts: allConcepts,
152
+ // allFacts: allFacts,
153
+ // generatedConcepts: generatedConceptsSet,
154
+ // generatedFacts: generatedFactsSet,
155
+ remainingConcepts: remainingConcepts,
156
+ remainingFacts: remainingFacts,
157
+ };
158
+ }
159
+ }
@@ -6,10 +6,10 @@ export class GenerateCards {
6
6
  this.openAiService = openAiService;
7
7
  }
8
8
 
9
- async generateCards(prompt: string, parsedContent: string) {
9
+ async generateCards(prompt: string, parsedContent: string, isGapFill: boolean) {
10
10
  let response = await this.openAiService?.sendRequest(prompt, parsedContent);
11
- console.log("response to card generation ", response);
12
- response["type"] = "card_gen";
11
+ // console.log("response to card generation ", response);
12
+ response["type"] = isGapFill ? "gap_fill":"card_gen";
13
13
  response.metadata = {
14
14
  "req_time": response.generated_at,
15
15
  "req_type": response.type,
@@ -31,24 +31,27 @@ export class GenerateCards {
31
31
  const missing_concepts = generatedData.generated_content.missing_concepts;
32
32
  const missing_facts = generatedData.generated_content.missing_facts;
33
33
  const unparsedTestCards = generatedData.generated_content.test_cards;
34
-
35
- for (let elem of unparsedTestCards) {
36
- if (elem.type == "flash") {
37
- cardData.push(this.parseFlashCard(elem));
38
- } else if (elem.type == "mcq") {
39
- cardData.push(this.parseMcqCard(elem));
40
- } else if (elem.type == "cloze") {
41
- cardData.push(this.parseClozeCard(elem));
42
- } else if (elem.type == "match") {
43
- cardData.push(this.parseMatchCard(elem));
44
- }
34
+ const type = generatedData.type;
35
+ if(unparsedTestCards !== undefined && unparsedTestCards.length != 0) {
36
+ for (let elem of unparsedTestCards) {
37
+ if (elem.type == "flash") {
38
+ cardData.push(this.parseFlashCard(elem));
39
+ } else if (elem.type == "mcq") {
40
+ cardData.push(this.parseMcqCard(elem));
41
+ } else if (elem.type == "cloze") {
42
+ cardData.push(this.parseClozeCard(elem));
43
+ } else if (elem.type == "match") {
44
+ cardData.push(this.parseMatchCard(elem));
45
45
  }
46
+ }
47
+ }
48
+
46
49
  usage_data["created_at"] = created_at;
47
- usage_data["type"] = "card_gen";
48
50
 
49
51
  return {
50
52
  status_code: status_code,
51
53
  metadata: usage_data,
54
+ type: type,
52
55
  missing_concepts: missing_concepts,
53
56
  missing_facts: missing_facts,
54
57
  cards_data: cardData,
@@ -24,7 +24,7 @@ json
24
24
  {
25
25
  "type": "flash" | "mcq" | "cloze" | "match",
26
26
  "card_content": { "front": "...", "back": "..." | "prompt": "...", "choices": [ ... ] | "prompt": "...", "options": [ ... ] | "right_choice 1": "...", "left_choice 1": "..." },
27
- "card_reference": "source_title#heading",
27
+ "card_reference": "heading",
28
28
  "concepts": ["Concept1", "Concept2", "..."],
29
29
  "facts": ["Fact1", "Fact2", "..."]
30
30
  }
@@ -32,11 +32,10 @@ json
32
32
 
33
33
  **Criteria**
34
34
  • Each test card must include at least one concept or fact.
35
- Deprioritize the Flashcards, must not exceed 15% of the total number of cards.
35
+ • Flashcards must not exceed 15% of the total number of cards.
36
36
  • Each concept and fact must have at least one test card.
37
37
 
38
38
  Further instructions are provided below.
39
-
40
39
  Concepts are fundamental ideas that form the basis of knowledge in any discipline. They help organize and explain information, making it accessible and relatable.
41
40
 
42
41
  You are provided with a list of identified concepts. Review this list and the content to determine if any concepts are missing.
@@ -64,7 +63,7 @@ json
64
63
  {
65
64
  "missing_facts": ["fact1", "fact2", "fact3", "..."]
66
65
  }
67
- After you have the complete list of concepts and facts, including any missing ones you identified, proceed to generate test cards for each.
66
+ After you have the complete list of concepts and facts, including any missing ones you identified, proceed to generate test cards for each.
68
67
 
69
68
  1. Clarity: Ensure the test content is clear and unambiguous.
70
69
  2. Specificity: Be specific about what you are asking. Avoid vague or overly broad questions or prompts.
@@ -74,23 +73,29 @@ json
74
73
  Test cards must be one of the following types:
75
74
 
76
75
  1. Flashcards: Have a front and back.
76
+ 2. A flashcard consists of two sides: a front and a back. Both the front and back text content must not exceed more than 300 characters in length.
77
77
 
78
- json
78
+ json schema for Flash Cards:
79
79
  {
80
80
  "type": "flash",
81
81
  "card_content": {
82
- "front": "<content for the front>",
83
- "back": "<content for the back>"
82
+ "front": "<content for the front of the flashcard>",
83
+ "back": "<content for the back of the flashcard>"
84
84
  },
85
- "card_reference": "source_title#heading",
85
+ "card_reference": "heading",
86
86
  "concepts": ["Concept1", "Concept2", "..."],
87
87
  "facts": ["Fact1", "Fact2", "..."]
88
88
  }
89
89
 
90
- - Each side must not exceed 300 characters.
90
+
91
91
  2. Multiple Choice Questions (MCQ): Provide multiple choices to pick from. One or more should be correct.
92
+ • Minimum choices required: 2
93
+ • Maximum choices allowed: 8
94
+ • Minimum correct choices required: 1
95
+ • Maximum character length for the prompt: 320
96
+ • Maximum character length for each choice: 42
92
97
 
93
- json
98
+ json schema for mcqs
94
99
  {
95
100
  "type": "mcq",
96
101
  "card_content": {
@@ -101,156 +106,55 @@ json
101
106
  "... up to 8 choices"
102
107
  ]
103
108
  },
104
- "card_reference": "source_title#heading",
109
+ "card_reference": "heading",
105
110
  "concepts": ["Concept1", "Concept2", "..."],
106
111
  "facts": ["Fact1", "Fact2", "..."]
107
112
  }
108
113
 
114
+ 3. Cloze:
115
+ Fill-in-the-blank style test card. Use double curly braces {{}} to indicate a cloze this is absolute necessagr
109
116
  • Minimum choices required: 2
110
117
  • Maximum choices allowed: 8
111
118
  • Minimum correct choices required: 1
112
119
  • Maximum character length for the prompt: 320
113
- • Maximum character length for each choice: 42
114
-
115
- 3. Cloze: Fill-in-the-blank style test card. Use double curly braces {{}} to indicate a cloze.
120
+ • Maximum character length for an individual cloze: 90
116
121
 
117
- json
122
+ json schema for cloze
118
123
  {
119
124
  "type": "cloze",
120
- "card_content":{
121
- "text": "<clozed_text>",
122
- "options": [
123
- {"option" : "<cloze_0>", "cloze" : "<position_0>"},
124
- {"option" : "<cloze_1>", "cloze" : "<position_1>,
125
- {"option" : "<cloze_2>", "cloze" : "<position_2>"},
126
- ....
127
- {"option" : "<cloze_6>", "cloze" : "<position_6>"},
125
+ "card_content": {
126
+ "text": "Accidentals in music denote {{c0:notes}} that do not belong to the {{c1:scale}} or {{c2:mode}} indicated by the key signature.",
127
+ "options": [
128
+ {"option": "notes", "cloze": "c0"},
129
+ {"option": "scale", "cloze": "c1"},
130
+ {"option": "mode", "cloze": "c2"},
131
+ {"option": "chords", "cloze": null},
132
+ "... up to 8 choices"
128
133
  ]
129
-
130
- }
131
- "card_reference": "source_title#heading",
134
+ },
135
+ "card_reference": "heading",
132
136
  "concepts": ["Concept1", "Concept2", "..."],
133
137
  "facts": ["Fact1", "Fact2", "..."]
134
138
  }
135
139
 
136
- • Minimum choices required: 2
137
- • Maximum choices allowed: 8
138
- • Minimum correct choices required: 1
139
- • Maximum character length for the prompt: 320
140
- • Maximum character length for an individual cloze: 90
140
+
141
141
 
142
142
  4. Match: Pairing items.
143
+ • Maximum character length for each item in a pair: 42
143
144
 
144
- json
145
+ json schema for match
145
146
  {
146
147
  "type": "match",
147
148
  "card_content": {
148
- "<left_text1>": "<right_text1>",
149
- "<left_text2>": "<right_text2>",
150
- "<left_text3>": "<right_text3>",
151
- ...
152
- "<left_text8>": "<right_text8>"
153
- }
154
- "card_reference": "source_title#heading",
149
+ "right_choice 1": "left_choice 1",
150
+ "right_choice 2": "left_choice 2",
151
+ "... up to 8 total pairs"
152
+ },
153
+ "card_reference": "heading",
155
154
  "concepts": ["Concept1", "Concept2", "..."],
156
155
  "facts": ["Fact1", "Fact2", "..."]
157
156
  }
158
157
 
159
- • Maximum character length for each item in a pair: 42
160
-
161
-
162
- The schema for each card type is below.
163
-
164
- A flashcard consists of two sides: a front and a back. Both the front and back text content must not exceed more than 300 characters in length.
165
-
166
- The content schema should be represented in this manner:
167
- json
168
- {
169
- "front": "<content for the front of the flashcard>",
170
- "back": "<content for the back of the flashcard>"
171
- }
172
-
173
-
174
- The schema for an mcq card is shown below.
175
-
176
- json
177
- {
178
- "prompt": "<question text>",
179
- "choices":
180
- [
181
- {
182
- choice: "choice 1",
183
- is_correct: true or false
184
- },
185
- {
186
- choice: "choice 2",
187
- is_correct: true or false
188
- }
189
- "... up to 8 choices"
190
- ]
191
- }
192
-
193
- Minimum choices required: 2
194
- Maximum choices allowed: 8
195
- Minimum correct choices required: 1
196
- Maximum character length for the prompt: 320
197
- Maximum character length for each choice: 42
198
-
199
-
200
- For questions of the "type": "cloze", which refers to a fill-in-the-blank style question, the format is outlined below. I have used the sample text here because it is easier to illustrate the schema with an example:
201
-
202
- json
203
- {
204
- "prompt": "Accidentals in music denote {{c0:notes}} that do not belong to the {{c1:scale}} or {{c2:mode}} indicated by the key signature."
205
- "options":
206
- [
207
- {
208
- "option: "notes",
209
- "cloze": "c0"
210
- },
211
- {
212
- "option: "chords",
213
- "cloze": null
214
- },
215
- {
216
- "option: "scale",
217
- "cloze": "c1"
218
- },
219
- {
220
- "option: "mode",
221
- "cloze": "c2"
222
- },
223
-
224
- {
225
- "option: "tilda",
226
- "cloze": null
227
- },
228
- {
229
- "option: "score",
230
- "cloze": null
231
- },
232
- "... up to a maximum of 8 choices total"
233
- ]
234
- }
235
-
236
- Minimum choices required: 2
237
- Maximum choices allowed: 8
238
- Minimum correct choices required: 1
239
- Maximum character length for the prompt: 320
240
- Maximum character length for an individual cloze: 90
241
-
242
- The schema for match type cards are as follows.
243
- json
244
- {
245
- "<left_text1>": "<right_text1>",
246
- "<left_text2>": "<right_text2>",
247
- "<left_text3>": "<right_text3>",
248
- ...
249
- "<left_text8>": "<right_text8>"
250
- }
251
-
252
- Maximum character length for each item in a pair: 42
253
- Each test card needs 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 reference schema is as follows: source_title#main_heading, where #main_heading is optional.
254
158
  Once you are done generating the test cards. Go back and evaulate the full list of concepts and fact that include any of the missing concepts or facts along with the list that was provided as the input.
255
159
 
256
160
  Are there any concept or fact that don't have a test card yet? If yes, go back and create one.
@@ -264,7 +168,6 @@ Once you are done generating the test cards, review the full list of concepts an
264
168
  3. Repeat this step until all concepts and facts are covered.
265
169
 
266
170
  Only stop generating test questions once you believe there is sufficient testing material for learners to fully understand the concepts and remember the facts. The same concept or fact can have multiple test cards, so continue creating test cards until you are confident that there are enough for learners to fully grasp the source material.
267
-
268
171
  `;
269
172
 
270
173
 
package/src/index.ts CHANGED
@@ -4,11 +4,11 @@
4
4
  // import { returnTypologyPrompt } from "./constants/prompts/typology_prompt";
5
5
  // import { GenerateArgs } from "./utils/generate_args";
6
6
  // import { returnFields, returnHeadings, returnSourceData } from "./constants/source_data";
7
- import { OnlyEverGenerator } from "./bootstrap/app";
8
7
  // import config from "./config";
9
8
  // const app = express();
10
9
  // const port = 3000;
11
10
 
11
+ import { OnlyEverGenerator } from "./bootstrap/app";
12
12
 
13
13
 
14
14
  /// While Publishing the package , and using this code as a separate npm module
@@ -34,7 +34,7 @@ export {OnlyEverGenerator};
34
34
  // let content = returnSourceData().toString()
35
35
  // let headings = returnHeadings();
36
36
  // // let aiRequest = await openAIRequest(prompt,content);
37
- // let aiRequest = await oeGen.generateCard(prompt,content);
37
+ // let aiRequest = await oeGen.generateCard(prompt,content, false);
38
38
  // res.send(aiRequest);
39
39
  // });
40
40