only_ever_generator 0.5.2 → 0.5.3

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.
Files changed (33) hide show
  1. package/dist/bootstrap/app.js.map +1 -0
  2. package/dist/card_gen/generate_cards.js.map +1 -0
  3. package/dist/constants/api_constants.js.map +1 -0
  4. package/dist/constants/prompt_data.js.map +1 -0
  5. package/dist/constants/prompts/card_gen_prompt.js +93 -164
  6. package/dist/constants/prompts/card_gen_prompt.js.map +1 -0
  7. package/dist/constants/prompts/typology_prompt.js +21 -20
  8. package/dist/constants/prompts/typology_prompt.js.map +1 -0
  9. package/dist/constants/source_data.js.map +1 -0
  10. package/dist/gap_fill/calculate_gap_fill.js.map +1 -0
  11. package/dist/index.js +16 -21
  12. package/dist/parse/parse_card/parse_cloze_card.js +54 -17
  13. package/dist/parse/parse_card/parse_cloze_card.js.map +1 -0
  14. package/dist/parse/parse_card/parse_match_card.js +30 -8
  15. package/dist/parse/parse_card/parse_match_card.js.map +1 -0
  16. package/dist/parse/parse_card/parse_mcq_card.js.map +1 -0
  17. package/dist/parse/parse_card_response.js +1 -1
  18. package/dist/parse/parse_card_response.js.map +1 -0
  19. package/dist/parse/parse_source_content.js.map +1 -0
  20. package/dist/parse/response_format_card.js.map +1 -0
  21. package/dist/parse/response_format_typology.js.map +1 -0
  22. package/dist/services/open_ai_service.js.map +1 -0
  23. package/dist/typology_gen/generate_typology.js.map +1 -0
  24. package/dist/utils/generate_args.js.map +1 -0
  25. package/dist/utils/parse_openai_response.js.map +1 -0
  26. package/package.json +1 -1
  27. package/prompts.json +23 -0
  28. package/src/constants/prompts/card_gen_prompt.ts +93 -164
  29. package/src/constants/prompts/typology_prompt.ts +21 -20
  30. package/src/index.ts +12 -23
  31. package/src/parse/parse_card/parse_cloze_card.ts +50 -16
  32. package/src/parse/parse_card/parse_match_card.ts +42 -7
  33. package/src/parse/parse_card_response.ts +1 -1
@@ -1,13 +1,18 @@
1
1
  const typologyPromptString = `
2
- You are a dedicated assistant that categorizes and summarizes educational content. You will process educational content (in JSON format) that represents text from diverse sources such as PDFs, book chapters, videos, and websites. Follow these steps:
2
+ You are a dedicated assistant that categorizes and summarizes educational content. You will process educational content (in JSON format) that represents text from diverse sources such as wikipedia, markdown notes, PDFs, book chapters, and websites.
3
+ You will be provided with the following:
4
+ 1. Title of the source
5
+ 2. A list of main headings in the source
6
+ 3. The source content
3
7
 
8
+ Follow these steps:
4
9
  1. Classify the content into one to three predefined fields of knowledge.
5
10
  2. Extract key concepts within the content. Be exhaustive and thorough.
6
- 3. Extract concrete facts that are relevant to the subject and referenced in the content.
7
- 4. Decide whether the provided text has educational value and should be used to generate test material and quizzes based on the identified concepts and facts.
11
+ 3. Extract concrete and relevant facts that are referenced in the content. Be exhaustive and thorough.
12
+ 4. Decide whether the content has any educational value and should be used to generate test material and quizzes based on the identified concepts and facts.
8
13
  5. If the generate_cards is true then summarize the content using a series of summary cards.
9
14
 
10
- Please format your findings in this JSON schema:
15
+ Output your answer as valid JSON, in the form:
11
16
  json
12
17
  {
13
18
  "field": ["primary_field", "secondary_field", "tertiary_field"],
@@ -27,10 +32,10 @@ json
27
32
  },
28
33
  {...}
29
34
  ],
30
- "generate_cards": {
35
+ "generate_cards": [
31
36
  state: true or false,
32
37
  reason: "reason for marking the source as false. Leave empty for true."
33
- },
38
+ ],
34
39
  "summary_cards": ["summary_card1_content", "summary_card2_content", "summary_card3_content", "..."]
35
40
  }
36
41
 
@@ -58,9 +63,9 @@ Every source must be placed under a field. This is the broadest category of know
58
63
  Extract key concepts within the content after classifying the field. This is a crucial part of the exercise. Be exhaustive and thorough.
59
64
 
60
65
  1. **Definition of a Concept**: Concepts are fundamental ideas that form the basis of knowledge in any discipline. They help organize and explain information, making it accessible and relatable.
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.
66
+ 2. **Inclusion Criteria**: Include a concept only if it is discussed in detail and is an important part of the subject matter of the source.
62
67
  3. **How to describe a concept**: The concept should be described so that a reader can comprehend the gist of it.
63
- 4. **Character Limit**: Maintain a limit of 60 characters for the to ensure each concept is concise yet informative.
68
+ 4. **Character Limit**: Maintain a limit of 90 characters to ensure each concept is concise yet informative.
64
69
  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
70
 
66
71
  List the concepts in the following JSON format:
@@ -74,12 +79,11 @@ json
74
79
  },
75
80
  {...}
76
81
  ]
77
-
78
82
  After classifying the content and identifying key concepts, proceed to extract and list verifiable facts.
79
83
 
80
84
  1. **Definition of a Fact**: Ensure each fact is a standalone piece of information that is concrete and can be independently verified.
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
- 3. **Character Limit**: Maintain a limit of 60 characters for the to ensure each message is concise yet informative.
85
+ 2. **Selection Criteria**: Inlcude facts based on their significance to the content's main themes or concepts, their educational value and their foundational role in the subject.
86
+ 3. **Character Limit**: Maintain a limit of 90 characters for the to ensure each message is concise yet informative.
83
87
  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
88
 
85
89
  List the facts in the following JSON format:
@@ -93,22 +97,17 @@ json
93
97
  },
94
98
  {...}
95
99
  ]
100
+ After you have examined the content —its field, its concepts, and its facts— determine whether it justifies the creation of quiz materials.
96
101
 
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.
98
-
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.
100
-
101
- 1. **Value Assessment**: Determine if the concepts and facts are essential for understanding the broader topic, are likely to be used in practical scenarios, or help in achieving educational benchmarks.
102
- 2. **Criteria for Material Generation**: Generate testing materials if the concepts and facts are central to the content, have broad applicability, and are likely to reinforce or expand the learner’s knowledge significantly.
102
+ Consider whether these elements offer the average learner meaningful insights, practical uses, or serve important educational aims. If, in your judgment, the material falls short of providing such value, explain why in fewer than 90 characters.
103
103
 
104
- Make your decision using this criterion and reflect it in the JSON format as follows:
104
+ Reflect your in the JSON format as follows:
105
105
 
106
106
  json
107
107
  "generate_cards":
108
108
  { state: true or false,
109
109
  reason: "reason for marking the source as false. Leave empty for true."
110
110
  }
111
-
112
111
  After analyzing the content, identifying key concepts, and facts, summarize the material using a series of engaging and informative cards.
113
112
 
114
113
  These cards should capture the essence of the content while highlighting the critical concepts and facts that you previously identified.
@@ -124,9 +123,11 @@ Format your output in JSON as follows:
124
123
 
125
124
  json
126
125
  {
127
- "summary_cards": ["summary_card1_content", "summary_card2_content", "summary_card3_content", "..."]
126
+ "summary_cards": ["summary_card1_content", "summary_card2_content", "summary_card3_content", "... up to 8 summary cards"]
128
127
  }
129
128
 
129
+
130
+
130
131
  `;
131
132
 
132
133
 
package/src/index.ts CHANGED
@@ -7,8 +7,6 @@
7
7
  // import config from "./config";
8
8
  // const app = express();
9
9
  // const port = 3000;
10
-
11
- import { OnlyEverGenerator } from "./bootstrap/app";
12
10
  // import { returnPromptData } from "./constants/prompt_data";
13
11
  // import { GenerateCards } from "./card_gen/generate_cards";
14
12
  // import { OpenAiService } from "./services/open_ai_service";
@@ -17,13 +15,16 @@ import { OnlyEverGenerator } from "./bootstrap/app";
17
15
  // import { returnCardGenPrompt } from "./constants/prompts/card_gen_prompt";
18
16
  // import { GenerateArgs } from "./utils/generate_args";
19
17
 
18
+ import { OnlyEverGenerator } from "./bootstrap/app";
19
+
20
+
20
21
  /// While Publishing the package , and using this code as a separate npm module
21
22
  /// uncomment the below line and comment all the others, expect the import of OnlyEverGenerator
22
23
  export {OnlyEverGenerator};
23
24
 
24
- //. All the Codes Below uses express and are strictly for development purpose, while publishing the package, comment everything
25
- //below this line
26
- // let oeGen = new OnlyEverGenerator(config.openAIKey, "gpt-4o", {
25
+ // . All the Codes Below uses express and are strictly for development purpose, while publishing the package, comment everything
26
+ // below this line
27
+ // let oeGen = new OnlyEverGenerator(config.openAIKey, "gpt-4o-mini", {
27
28
  // prompt: returnPromptData(),
28
29
  // content: returnSourceData(),
29
30
  // });
@@ -60,24 +61,12 @@ import { OnlyEverGenerator } from "./bootstrap/app";
60
61
  // res.send(parsedData)
61
62
  // });
62
63
 
63
- // // app.get("/typology", async (req, res) => {
64
- // // {
65
- // // let typologyPrompt = returnTypologyPrompt();
66
- // // let cardPrompt = returnCardGenPrompt();
67
- // // let args = new GenerateArgs(
68
- // // true,
69
- // // true,
70
- // // false,
71
- // // {
72
- // // typology_prompt: typologyPrompt,
73
- // // card_gen_prompt: cardPrompt,
74
- // // summary_prompt: "",
75
- // // }
76
- // // )
77
- // // let typologyRequest = await oeGen.generate(false, true);
78
- // // res.send(typologyRequest);
79
- // // }
80
- // // });
64
+ // app.get("/typology", async (req, res) => {
65
+ // {
66
+ // let typologyRequest = await oeGen.generate(true, true);
67
+ // res.send(typologyRequest);
68
+ // }
69
+ // });
81
70
 
82
71
  // app.listen(port, () => {
83
72
  // console.log(`Example app listening at http://localhost:${port}`);
@@ -1,10 +1,21 @@
1
1
  export class ParseClozeCard {
2
2
  parse(data: any) {
3
3
  try {
4
- let displayTitle = this._generateClozeCardDisplayTitle(
5
- data.card_content.prompt,
6
- data.card_content.options
7
- );
4
+ const content = data.card_content;
5
+ let correctOptions = content.correct_options;
6
+ let incorrectOptions = content.incorrect_options;
7
+ let allOptions = [...correctOptions, ...incorrectOptions];
8
+ let displayTitle = this._generateClozeCardDisplayTitle(data.card_content.prompt, allOptions);
9
+ let preparedData = this._prepareQuestionAndCorrectAnswers(content.prompt, correctOptions);
10
+ let finalQuestion = preparedData.prompt;
11
+ let parsedCorrectOptions = preparedData.options;
12
+ let parsedIncorrectoptions = incorrectOptions.map((e:any)=>{
13
+ return {
14
+ "option":e,
15
+ "cloze": "null"
16
+ };
17
+ });
18
+ const finalParsedOptions = [...parsedCorrectOptions,...parsedIncorrectoptions];
8
19
  let clozeCardData = {
9
20
  type: {
10
21
  category: "learning",
@@ -13,8 +24,8 @@ export class ParseClozeCard {
13
24
  heading: data.card_reference,
14
25
  displayTitle: displayTitle,
15
26
  content: {
16
- question: data.card_content.prompt,
17
- options: data.card_content.options,
27
+ question: finalQuestion,
28
+ options: finalParsedOptions,
18
29
  },
19
30
  concepts: data.concepts,
20
31
  facts: data.facts,
@@ -28,20 +39,16 @@ export class ParseClozeCard {
28
39
  }
29
40
 
30
41
  _generateClozeCardDisplayTitle(question: string, answers: Array<any>) {
42
+ try{
31
43
  let optionsString = "";
32
44
  if (answers.length !== 0) {
33
45
  optionsString = answers
34
- .map((item: { option: any }) => {
35
- if (item.option !== undefined) {
36
- return item.option;
37
- } else {
38
- return "";
39
- }
40
- })
41
46
  .join(", ");
42
47
  }
43
48
 
44
- return `${question} ---- ${optionsString}`;
49
+ return `${question} ---- ${optionsString}`;}catch(e){
50
+ throw Error("Error in generating display title");
51
+ }
45
52
  }
46
53
 
47
54
  /// validate the cloze card
@@ -53,6 +60,33 @@ export class ParseClozeCard {
53
60
  // 6. Less than 2 options
54
61
  // 7. Max character for individual cloze: 90
55
62
 
63
+ _prepareQuestionAndCorrectAnswers(rawPrompt:String, correctOptions: Array<any>){
64
+ try{
65
+ var finalCorrectOptions = <any>[];
66
+ const regex = /{{(.*?)}}/g;
67
+
68
+ const transformed = rawPrompt.replace(regex, (match, p1) => {
69
+ // p1 is the captured group inside {{ }} (e.g., "fruit", "green")
70
+ const idx = correctOptions.indexOf(p1);
71
+ if (idx !== -1) {
72
+ let cloze = `c${idx}`;
73
+ finalCorrectOptions.push( {
74
+ "option": p1,
75
+ "cloze": cloze,
76
+ });
77
+ return `{{c${idx}:${p1}}}`;
78
+ }
79
+ return match; // If not found in correct_options, leave as is or handle accordingly
80
+ });
81
+ return {
82
+ "prompt": transformed,
83
+ "options": finalCorrectOptions
84
+ }} catch(e){
85
+ throw Error("Error in preparing question and correct answers");
86
+ }
87
+
88
+ }
89
+
56
90
  _validateCloze(clozeCard: any) {
57
91
  let clozeRegex = /\{\{c(\d+):([^}]+)\}\}/g;
58
92
 
@@ -83,8 +117,8 @@ export class ParseClozeCard {
83
117
  throw Error(" Clozes in question doesnt match to clozes in options");
84
118
  }
85
119
  return clozeCard;
86
- } catch (e) {
87
- return false;
120
+ } catch (e: any) {
121
+ throw Error(`Error in validating cloze card ${e.message}`);
88
122
  }
89
123
  }
90
124
  }
@@ -1,9 +1,20 @@
1
1
  import { match } from "assert";
2
2
 
3
+ type InputItem = {
4
+ left_item: string;
5
+ right_item: string;
6
+ };
7
+
8
+ type OutputItem = {
9
+ left_item: string;
10
+ right_item: string[];
11
+ };
12
+
3
13
  export class ParseMatchCard {
4
14
  parse(cardData: any) {
5
15
  try {
6
16
  let content = cardData.card_content;
17
+ const finalContent =this._parseMatchContent(content);
7
18
 
8
19
  let displayTitle = this._generateMatchCardDisplayTitle(content);
9
20
  let matchCard = {
@@ -11,8 +22,8 @@ export class ParseMatchCard {
11
22
  category: "learning",
12
23
  sub_type: cardData.type,
13
24
  },
14
- heading: cardData.card_reference,
15
- content: content,
25
+ heading: cardData.card_content.card_reference,
26
+ content: finalContent,
16
27
  // content: cardData.card_content,
17
28
  displayTitle: displayTitle,
18
29
  concepts: cardData.concepts,
@@ -26,11 +37,13 @@ export class ParseMatchCard {
26
37
  }
27
38
  }
28
39
 
40
+
41
+
29
42
  _generateMatchCardDisplayTitle(answers: any) {
30
43
  let titles: string[] = [];
31
44
  let counter = 65;
32
45
  for (let data of answers) {
33
- let value = data.right_item.join(",");
46
+ let value = data.right_item;
34
47
  let leftData = data.left_item;
35
48
  let letter = String.fromCharCode(counter);
36
49
  titles.push(`${letter}. ${leftData} -- ${value}`);
@@ -40,16 +53,38 @@ export class ParseMatchCard {
40
53
  return displayTitle;
41
54
  }
42
55
 
56
+ _parseMatchContent = (input: InputItem[]): OutputItem[] => {
57
+ const grouped = input.reduce<Record<string, OutputItem>>((acc, { left_item, right_item }) => {
58
+ if (!acc[left_item]) {
59
+ acc[left_item] = { left_item, right_item: [] };
60
+ }
61
+ acc[left_item].right_item.push(right_item);
62
+ return acc;
63
+ }, {});
64
+
65
+ return Object.values(grouped);
66
+ };
67
+
43
68
  _validateMatch(matchCard: any){
44
69
  let matches = matchCard.content;
70
+ let content = [];
45
71
  try{
72
+ if(matches.length < 1 || matches.length > 8){
73
+ throw Error("Invalid number of matches");
74
+ }
75
+
46
76
  for(let elem of matches){
47
- if(elem.left_item.length > 24 || elem.left_item.length == 0){
48
- throw Error("Invalid Length of left item ");
49
- }else if(elem.right_item[0].length>24 || elem.right_item[0].length == 0){
50
- throw Error(" Invalid Length of right item")
77
+ if(elem.left_item.length <= 30 && elem.left_item.length != 0){
78
+ if(elem.right_item.length <= 40 && elem.right_item.length != 0){
79
+ content.push(elem);
51
80
  }
81
+ }
82
+ }
83
+ if(content.length >= 2){
84
+ matchCard.content = content;
52
85
 
86
+ }else{
87
+ throw Error("Invalid content");
53
88
  }
54
89
  return matchCard;
55
90
  }catch(e){
@@ -15,7 +15,7 @@ export class ParseCardResponse {
15
15
  if (elem.type == "flash") {
16
16
  const flashCard = this.parseFlashCard(elem);
17
17
  if (flashCard != null && flashCard) {
18
- this.parseFlashCard(flashCard);
18
+ cardData.push(flashCard);
19
19
  }
20
20
  } else if (elem.type == "mcq") {
21
21
  const mcqCard = new ParseMcqCard().parse(elem);