only_ever_generator 0.0.7 → 0.0.9

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.
@@ -11,23 +11,24 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.GenerateTypology = void 0;
13
13
  class GenerateTypology {
14
- constructor(openAiService, prompt, content) {
14
+ constructor(openAiService, prompt, content, expected_fields) {
15
15
  this.prompt = '';
16
16
  this.content = '';
17
17
  this.openAiService = openAiService;
18
18
  this.prompt = prompt;
19
19
  this.content = content;
20
+ this.expectedFields = expected_fields.map((elem) => elem.toLowerCase());
20
21
  }
21
22
  generate() {
22
23
  return __awaiter(this, void 0, void 0, function* () {
23
- var _a;
24
+ var _a, _b, _c;
24
25
  const response = yield ((_a = this.openAiService) === null || _a === void 0 ? void 0 : _a.sendRequest(this.prompt, this.content));
25
26
  response['type'] = 'typology';
26
27
  response.metadata = {
27
28
  "req_time": response.generated_at,
28
29
  "req_type": response.type,
29
- "req_tokens": response.usage_data.prompt_tokens,
30
- "res_tokens": response.usage_data.completion_tokens,
30
+ "req_tokens": (_b = response.usage_data) === null || _b === void 0 ? void 0 : _b.prompt_tokens,
31
+ "res_tokens": (_c = response.usage_data) === null || _c === void 0 ? void 0 : _c.completion_tokens,
31
32
  };
32
33
  if (response.status_code == 200) {
33
34
  return this.parseTypologyOnSuccess(response);
@@ -43,14 +44,21 @@ class GenerateTypology {
43
44
  return {
44
45
  status_code: 200,
45
46
  metadata: responseData.metadata,
46
- field: generatedContent.field,
47
+ field: this.parseFields(generatedContent.field),
47
48
  concepts: generatedContent.concepts,
48
49
  facts: generatedContent.facts,
49
50
  generate_cards: generatedContent.generate_cards,
50
51
  summary_cards: generatedContent.summary_cards,
51
- type: responseData.type,
52
+ type: responseData.type
52
53
  };
53
54
  }
55
+ parseFields(fields) {
56
+ const fieldKeys = ['primary_field', 'secondary_field', 'tertiary_field'];
57
+ return fields.slice(0, 3).map((item, index) => ({
58
+ [fieldKeys[index]]: item,
59
+ "reconcile": !(this.expectedFields.includes(item.toLowerCase()))
60
+ }));
61
+ }
54
62
  parseTypologyOnFailure(responseData) {
55
63
  return __awaiter(this, void 0, void 0, function* () {
56
64
  responseData.metadata.status = 'failed';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "only_ever_generator",
3
- "version": "0.0.7",
3
+ "version": "0.0.9",
4
4
  "main": "dist/index.js",
5
5
  "scripts": {
6
6
  "start": "nodemon dist/index.js",
@@ -1,18 +1,26 @@
1
- import { ParseSourceContent } from "../class/parse/parse_source_content";
2
- import { OpenAiService } from "../class/services/open_ai_service";
1
+ import { GenerateCards } from "../card_gen/generate_cards";
2
+ import { ParseSourceContent } from "../parse/parse_source_content";
3
+ import { OpenAiService } from "../services/open_ai_service";
3
4
  import { returnCardGenPrompt } from "../constants/prompts/card_gen_prompt";
4
5
  import { returnTypologyPrompt } from "../constants/prompts/typology_prompt";
5
6
  import { GenerateTypology } from "../typology_gen/generate_typology";
6
7
  import { GenerateArgs } from "../utils/generate_args";
8
+ import { returnFields } from "../constants/source_data";
9
+ import { returnTypologyData } from "../parse/response_format_typology";
10
+
11
+
12
+ /// OnlyEverGenerator
7
13
 
8
14
  export class OnlyEverGenerator{
9
15
  public api_key: string = '';
10
16
  public openAiService: OpenAiService;
11
17
  parsedContent: string = '';
12
- constructor(apiKey:string, model: string, content: Array<any>){
18
+ expectedFields: Array<string>
19
+ constructor(apiKey:string, model: string, content: Array<any>, expected_fields: Array<string>){
13
20
  this.api_key = apiKey;
14
21
  this.openAiService = new OpenAiService(apiKey,model ?? 'gpt-3.5-turbo-1106');
15
22
  this.parsedContent = new ParseSourceContent(content).parse();
23
+ this.expectedFields = returnFields()
16
24
  };
17
25
 
18
26
  typologyResponse = {};
@@ -23,8 +31,8 @@ export class OnlyEverGenerator{
23
31
 
24
32
 
25
33
  async generate(
26
- generate_card : boolean = false,
27
34
  generate_typology: boolean =false,
35
+ generate_card : boolean = false,
28
36
  ): Promise<Array<any>> {
29
37
  let typologyPrompt = returnTypologyPrompt();
30
38
  let cardPrompt = returnCardGenPrompt();
@@ -46,7 +54,6 @@ export class OnlyEverGenerator{
46
54
  this.typologyResponse = await this.generateTypology(args.prompts.typology_prompt ?? '');
47
55
  responseToReturn.push(this.typologyResponse);
48
56
  }else if(elem == 'generate_card'){
49
-
50
57
  this.cardgenResponse = await this.generateCard(args.prompts.card_gen_prompt ?? '', this.parsedContent + JSON.stringify(this.typologyResponse));
51
58
  responseToReturn.push(this.cardgenResponse);
52
59
  }
@@ -61,16 +68,19 @@ export class OnlyEverGenerator{
61
68
 
62
69
 
63
70
  async generateCard(prompt: string, content: string){
64
- let response = await this.openAiService?.sendRequest(prompt,this.parsedContent);
65
- response['type'] = 'card_gen';
66
- return response;
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;
67
76
  }
68
77
 
69
78
  async generateTypology(prompt:string){
70
79
  let response = await new GenerateTypology(
71
80
  this.openAiService,
72
81
  prompt,
73
- this.parsedContent
82
+ this.parsedContent,
83
+ this.expectedFields,
74
84
  ).generate();
75
85
  return response;
76
86
  }
@@ -0,0 +1,192 @@
1
+ import { OpenAiService } from "../services/open_ai_service";
2
+
3
+ export class GenerateCards {
4
+ openAiService: OpenAiService;
5
+ constructor(openAiService: OpenAiService) {
6
+ this.openAiService = openAiService;
7
+ }
8
+
9
+ async generateCards(prompt: string, parsedContent: string) {
10
+ let response = await this.openAiService?.sendRequest(prompt, parsedContent);
11
+ console.log("response to card generation ", response);
12
+ response["type"] = "card_gen";
13
+ response.metadata = {
14
+ "req_time": response.generated_at,
15
+ "req_type": response.type,
16
+ "req_tokens": response.usage_data?.prompt_tokens,
17
+ "res_tokens": response.usage_data?.completion_tokens,
18
+ };
19
+ if(response.status_code == 200){
20
+ return this.parse(response);
21
+ } else {
22
+ return response;
23
+ }
24
+ }
25
+
26
+ parse(generatedData: any) {
27
+ const cardData = [];
28
+ const usage_data = generatedData.metadata;
29
+ const created_at = generatedData.created_at;
30
+ const status_code = generatedData.status_code;
31
+ const missing_concepts = generatedData.generated_content.missing_concepts;
32
+ const missing_facts = generatedData.generated_content.missing_facts;
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
+ }
45
+ }
46
+ usage_data["created_at"] = created_at;
47
+ usage_data["type"] = "card_gen";
48
+
49
+ return {
50
+ status_code: status_code,
51
+ metadata: usage_data,
52
+ missing_concepts: missing_concepts,
53
+ missing_facts: missing_facts,
54
+ cards_data: cardData,
55
+ };
56
+ }
57
+
58
+ parseFlashCard(data: any) {
59
+ let displayTitle = this.generateFlashCardDisplayTitle(
60
+ data.card_content.front,
61
+ data.card_content.back
62
+ );
63
+ let flashCardData = {
64
+ type: data.type,
65
+ heading: data.card_reference,
66
+ displayTitle: displayTitle,
67
+ content: {
68
+ front_content: data.card_content.front,
69
+ back_content: data.card_content.back,
70
+ },
71
+ concepts: data.concepts,
72
+ facts: data.facts,
73
+ };
74
+
75
+ return flashCardData;
76
+ }
77
+
78
+ generateFlashCardDisplayTitle(front: string, back: string) {
79
+ return `${front} ---- ${back}`;
80
+ }
81
+
82
+ parseMcqCard(data: any) {
83
+ let mcqAnswers = [];
84
+ for (let choice of data.card_content.choices) {
85
+ let answer = {
86
+ answer: choice.choice,
87
+ is_correct: choice.is_correct,
88
+ };
89
+ mcqAnswers.push(answer);
90
+ }
91
+ let displayTitle = this.generateMcqCardDisplayTitle(
92
+ data.card_content.prompt,
93
+ mcqAnswers
94
+ );
95
+ let mcqCard = {
96
+ type: data.type,
97
+ heading: data.card_reference,
98
+ displayTitle: displayTitle,
99
+ content: {
100
+ question: data.card_content.prompt,
101
+ answers: mcqAnswers,
102
+ },
103
+ concepts: data.concepts,
104
+ facts: data.facts,
105
+ };
106
+ return mcqCard;
107
+ }
108
+
109
+ generateMcqCardDisplayTitle(question: string, answers: any) {
110
+ let answersString = [];
111
+ for (let option of answers) {
112
+ let currentIndex = answers.indexOf(option) + 1;
113
+ let temp = `${currentIndex} . ${option.answer} `;
114
+ answersString.push(temp);
115
+ }
116
+ let resultString = answersString.join("");
117
+ let finalDisplayTitle = `${question} ---- ${resultString}`;
118
+ return finalDisplayTitle;
119
+ }
120
+
121
+ parseClozeCard(data: any) {
122
+ let displayTitle = this.generateClozeCardDisplayTitle(
123
+ data.card_content.text,
124
+ data.card_content.options
125
+ );
126
+ let clozeCardData = {
127
+ type: data.type,
128
+ heading: data.card_reference,
129
+ displayTitle: displayTitle,
130
+ content: {
131
+ question: data.card_content.text,
132
+ options: data.card_content.options,
133
+ },
134
+ concepts: data.concepts,
135
+ facts: data.facts,
136
+ };
137
+
138
+ return clozeCardData;
139
+ }
140
+
141
+ generateClozeCardDisplayTitle(question: string, answers: any) {
142
+ let optionsString = answers
143
+ .map((item: { option: any }) => item.option)
144
+ .join(", ");
145
+ return `${question} ---- ${optionsString}`;
146
+ }
147
+
148
+ parseMatchCard(cardData: any) {
149
+ let data = cardData.card_content;
150
+ const transformedData: { [key: string]: string[] } = {};
151
+
152
+ for (let key in data) {
153
+ if (data.hasOwnProperty(key)) {
154
+ transformedData[key] = [data[key]];
155
+ // let value = data[key].replace(/[\[\]]/g, '');
156
+ // let items = data[key].split(',').map((item: string) => item.trim());
157
+ // map.set(key, items);
158
+ // }
159
+ }
160
+ let displayTitle = this.generateMatchCardDisplayTitle(transformedData);
161
+ let matchCard = {
162
+ type: cardData.type,
163
+ heading: cardData.card_reference,
164
+ content: transformedData,
165
+ // content: cardData.card_content,
166
+ displayTitle: displayTitle,
167
+ concepts: cardData.concepts,
168
+ facts: cardData.facts,
169
+ };
170
+
171
+ return matchCard;
172
+ }
173
+ }
174
+
175
+ generateMatchCardDisplayTitle(answers: any) {
176
+ let titles: string[] = [];
177
+ let counter = 65;
178
+ for (let key in answers) {
179
+ if (answers.hasOwnProperty(key)) {
180
+ let value = answers[key];
181
+ // let items = value.split(',').map((item: string) => item.trim());
182
+ // items.forEach((item: any) => {
183
+ let letter = String.fromCharCode(counter);
184
+ titles.push(`${letter}. ${key} -- ${value}`);
185
+ counter++;
186
+ // });
187
+ }
188
+ }
189
+ let displayTitle = titles.join(",");
190
+ return displayTitle;
191
+ }
192
+ }
@@ -0,0 +1,3 @@
1
+ export function openAiEndPoint(){
2
+ return 'https://api.openai.com/v1/chat/completions';
3
+ }
@@ -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
  }
@@ -36,7 +36,6 @@ json
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,46 +106,43 @@ 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
125
  "card_content": {
121
- "prompt": "Accidentals in music denote {{c0:notes}} that do not belong to the {{c1:scale}} or {{c2:mode}} indicated by the key signature.",
126
+ "text": "Accidentals in music denote {{c0:notes}} that do not belong to the {{c1:scale}} or {{c2:mode}} indicated by the key signature.",
122
127
  "options": [
123
128
  {"option": "notes", "cloze": "c0"},
124
129
  {"option": "scale", "cloze": "c1"},
125
130
  {"option": "mode", "cloze": "c2"},
126
- {"option": "chords", "cloze": "null"},
131
+ {"option": "chords", "cloze": null},
127
132
  "... up to 8 choices"
128
133
  ]
129
134
  },
130
- "card_reference": "source_title#heading",
135
+ "card_reference": "heading",
131
136
  "concepts": ["Concept1", "Concept2", "..."],
132
137
  "facts": ["Fact1", "Fact2", "..."]
133
138
  }
134
139
 
135
- • Minimum choices required: 2
136
- • Maximum choices allowed: 8
137
- • Minimum correct choices required: 1
138
- • Maximum character length for the prompt: 320
139
- • Maximum character length for an individual cloze: 90
140
+
140
141
 
141
142
  4. Match: Pairing items.
143
+ • Maximum character length for each item in a pair: 42
142
144
 
143
- json
145
+ json schema for match
144
146
  {
145
147
  "type": "match",
146
148
  "card_content": {
@@ -148,104 +150,11 @@ json
148
150
  "right_choice 2": "left_choice 2",
149
151
  "... up to 8 total pairs"
150
152
  },
151
- "card_reference": "source_title#heading",
153
+ "card_reference": "heading",
152
154
  "concepts": ["Concept1", "Concept2", "..."],
153
155
  "facts": ["Fact1", "Fact2", "..."]
154
156
  }
155
157
 
156
- • Maximum character length for each item in a pair: 42
157
-
158
-
159
- The schema for each card type is below.
160
-
161
- 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.
162
-
163
- The content schema should be represented in this manner:
164
- json
165
- {
166
- "front": "<content for the front of the flashcard>",
167
- "back": "<content for the back of the flashcard>"
168
- }
169
-
170
-
171
- The schema for an mcq card is shown below.
172
-
173
- json
174
- {
175
- "prompt": "<question text>",
176
- "choices":
177
- [
178
- {
179
- choice: "choice 1",
180
- is_correct: true or false
181
- },
182
- {
183
- choice: "choice 2",
184
- is_correct: true or false
185
- }
186
- "... up to 8 choices"
187
- ]
188
- }
189
-
190
- Minimum choices required: 2
191
- Maximum choices allowed: 8
192
- Minimum correct choices required: 1
193
- Maximum character length for the prompt: 320
194
- Maximum character length for each choice: 42
195
-
196
-
197
- 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:
198
-
199
- json
200
- {
201
- "prompt": "Accidentals in music denote {{c0:notes}} that do not belong to the {{c1:scale}} or {{c2:mode}} indicated by the key signature."
202
- "options":
203
- [
204
- {
205
- "option: "notes",
206
- "cloze": "c0"
207
- },
208
- {
209
- "option: "scale",
210
- "cloze": "c1"
211
- },
212
- {
213
- "option: "mode",
214
- "cloze": "c2"
215
- },
216
- {
217
- "option: "chords",
218
- "cloze": "null"
219
- },
220
- {
221
- "option: "tilda",
222
- "cloze": "null"
223
- },
224
- {
225
- "option: "score",
226
- "cloze": "null"
227
- },
228
- "... up to a maximum of 8 choices total"
229
- ]
230
- }
231
-
232
- Minimum choices required: 2
233
- Maximum choices allowed: 8
234
- Minimum correct choices required: 1
235
- Maximum character length for the prompt: 320
236
- Maximum character length for an individual cloze: 90
237
-
238
- The schema for match type cards are as follows.
239
- json
240
- {
241
- "right_choice 1": "left_choice 1",
242
- "right_choice 2": "left_choice 2"
243
- "right_choice 3": "left_choice 3"
244
- "... up to 8 total pairs"
245
- }
246
-
247
- Maximum character length for each item in a pair: 42
248
- 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.
249
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.
250
159
 
251
160
  Are there any concept or fact that don't have a test card yet? If yes, go back and create one.
@@ -266,4 +175,3 @@ export function returnCardGenPrompt(){
266
175
  return promptString;
267
176
  }
268
177
 
269
-