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.
- package/dist/bootstrap/app.js.map +1 -0
- package/dist/card_gen/generate_cards.js.map +1 -0
- package/dist/constants/api_constants.js.map +1 -0
- package/dist/constants/prompt_data.js.map +1 -0
- package/dist/constants/prompts/card_gen_prompt.js +93 -164
- package/dist/constants/prompts/card_gen_prompt.js.map +1 -0
- package/dist/constants/prompts/typology_prompt.js +21 -20
- package/dist/constants/prompts/typology_prompt.js.map +1 -0
- package/dist/constants/source_data.js.map +1 -0
- package/dist/gap_fill/calculate_gap_fill.js.map +1 -0
- package/dist/index.js +16 -21
- package/dist/parse/parse_card/parse_cloze_card.js +54 -17
- package/dist/parse/parse_card/parse_cloze_card.js.map +1 -0
- package/dist/parse/parse_card/parse_match_card.js +30 -8
- package/dist/parse/parse_card/parse_match_card.js.map +1 -0
- package/dist/parse/parse_card/parse_mcq_card.js.map +1 -0
- package/dist/parse/parse_card_response.js +1 -1
- package/dist/parse/parse_card_response.js.map +1 -0
- package/dist/parse/parse_source_content.js.map +1 -0
- package/dist/parse/response_format_card.js.map +1 -0
- package/dist/parse/response_format_typology.js.map +1 -0
- package/dist/services/open_ai_service.js.map +1 -0
- package/dist/typology_gen/generate_typology.js.map +1 -0
- package/dist/utils/generate_args.js.map +1 -0
- package/dist/utils/parse_openai_response.js.map +1 -0
- package/package.json +1 -1
- package/prompts.json +23 -0
- package/src/constants/prompts/card_gen_prompt.ts +93 -164
- package/src/constants/prompts/typology_prompt.ts +21 -20
- package/src/index.ts +12 -23
- package/src/parse/parse_card/parse_cloze_card.ts +50 -16
- package/src/parse/parse_card/parse_match_card.ts +42 -7
- 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,
|
|
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
|
|
7
|
-
4. Decide whether the
|
|
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
|
-
|
|
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
|
|
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
|
|
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**:
|
|
82
|
-
3. **Character Limit**: Maintain a limit of
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
64
|
-
//
|
|
65
|
-
//
|
|
66
|
-
//
|
|
67
|
-
//
|
|
68
|
-
//
|
|
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
|
-
|
|
5
|
-
|
|
6
|
-
|
|
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:
|
|
17
|
-
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
|
-
|
|
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:
|
|
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
|
|
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
|
|
48
|
-
|
|
49
|
-
|
|
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
|
-
|
|
18
|
+
cardData.push(flashCard);
|
|
19
19
|
}
|
|
20
20
|
} else if (elem.type == "mcq") {
|
|
21
21
|
const mcqCard = new ParseMcqCard().parse(elem);
|