only_ever_generator 8.4.6 → 8.4.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/dist/bootstrap/app.d.ts +6 -3
  2. package/dist/bootstrap/app.d.ts.map +1 -1
  3. package/dist/bootstrap/app.js +11 -17
  4. package/dist/bootstrap/app.js.map +1 -1
  5. package/dist/card_gen/generate_cards.d.ts +2 -3
  6. package/dist/card_gen/generate_cards.d.ts.map +1 -1
  7. package/dist/card_gen/generate_cards.js +22 -15
  8. package/dist/card_gen/generate_cards.js.map +1 -1
  9. package/dist/constants/prompt_data.d.ts +4 -4
  10. package/dist/constants/prompt_data.js +302 -302
  11. package/dist/constants/prompts/card_gen_prompt.js +160 -160
  12. package/dist/constants/prompts/typology_prompt.js +131 -131
  13. package/dist/constants/source_data.d.ts +171 -171
  14. package/dist/constants/source_data.js +973 -973
  15. package/dist/embedding_generation/local_consolidation.js +104 -104
  16. package/dist/helper/build_concept_facts_schema.d.ts +42 -42
  17. package/dist/helper/build_concept_facts_schema.js +44 -44
  18. package/dist/helper/qdrant_db_methods.d.ts.map +1 -1
  19. package/dist/helper/schema_helper/build_card_schema.d.ts +1 -9
  20. package/dist/helper/schema_helper/build_card_schema.d.ts.map +1 -1
  21. package/dist/helper/schema_helper/build_card_schema.js +47 -50
  22. package/dist/helper/schema_helper/build_card_schema.js.map +1 -1
  23. package/dist/helper/schema_helper/build_concept_facts_schema.d.ts +1 -1
  24. package/dist/helper/schema_helper/build_concept_facts_schema.d.ts.map +1 -1
  25. package/dist/helper/schema_helper/build_concept_facts_schema.js +20 -5
  26. package/dist/helper/schema_helper/build_concept_facts_schema.js.map +1 -1
  27. package/dist/helper/schema_helper/build_summary_schema.d.ts +1 -1
  28. package/dist/helper/schema_helper/build_summary_schema.d.ts.map +1 -1
  29. package/dist/helper/schema_helper/build_summary_schema.js +18 -7
  30. package/dist/helper/schema_helper/build_summary_schema.js.map +1 -1
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +5 -5
  33. package/dist/index.js.map +1 -1
  34. package/dist/parse/response_format_card.d.ts +176 -176
  35. package/dist/parse/response_format_card.js +371 -371
  36. package/dist/parse/response_format_typology.d.ts +1 -1
  37. package/dist/parse/response_format_typology.js +46 -46
  38. package/dist/services/get_prompts.d.ts +8 -7
  39. package/dist/services/get_prompts.d.ts.map +1 -1
  40. package/dist/services/get_prompts.js +69 -21
  41. package/dist/services/get_prompts.js.map +1 -1
  42. package/dist/typology_gen/generate_concept_facts.d.ts +2 -3
  43. package/dist/typology_gen/generate_concept_facts.d.ts.map +1 -1
  44. package/dist/typology_gen/generate_concept_facts.js +25 -15
  45. package/dist/typology_gen/generate_concept_facts.js.map +1 -1
  46. package/dist/typology_gen/generate_typology.d.ts +2 -1
  47. package/dist/typology_gen/generate_typology.d.ts.map +1 -1
  48. package/dist/typology_gen/generate_typology.js +24 -13
  49. package/dist/typology_gen/generate_typology.js.map +1 -1
  50. package/dist/typology_gen/summarize.d.ts +2 -3
  51. package/dist/typology_gen/summarize.d.ts.map +1 -1
  52. package/dist/typology_gen/summarize.js +24 -13
  53. package/dist/typology_gen/summarize.js.map +1 -1
  54. package/package.json +39 -38
  55. package/src/bootstrap/app.ts +418 -416
  56. package/src/card_gen/generate_cards.ts +347 -345
  57. package/src/config.ts +11 -11
  58. package/src/constants/api_constants.ts +7 -7
  59. package/src/constants/prompts/card_gen_prompt.ts +164 -164
  60. package/src/constants/prompts/typology_prompt.ts +139 -139
  61. package/src/embedding_generation/consolidation/global_consolidation.ts +96 -96
  62. package/src/embedding_generation/consolidation/local_consolidation.ts +141 -141
  63. package/src/embedding_generation/consolidation/write_consolidated_data.ts +98 -98
  64. package/src/embedding_generation/generate_embeddings.ts +42 -42
  65. package/src/embedding_generation/parse_embedding_response.ts +31 -31
  66. package/src/enums/card_type_enum.ts +6 -6
  67. package/src/gap_fill/calculate_gap_fill.ts +50 -50
  68. package/src/helper/get_id_from_title.ts +33 -33
  69. package/src/helper/mongo_helper.ts +29 -29
  70. package/src/helper/openai_helper.ts +20 -20
  71. package/src/helper/qdrant_db_methods.ts +77 -77
  72. package/src/helper/schema_helper/build_card_schema.ts +74 -98
  73. package/src/helper/schema_helper/build_classify_summarize_schema.ts +43 -43
  74. package/src/helper/schema_helper/build_concept_facts_schema.ts +45 -31
  75. package/src/helper/schema_helper/build_summary_schema.ts +43 -32
  76. package/src/index.ts +71 -73
  77. package/src/logger.ts +65 -65
  78. package/src/parse/parse_card/parse_cloze_card.ts +146 -146
  79. package/src/parse/parse_card/parse_flash_cards.ts +42 -42
  80. package/src/parse/parse_card/parse_match_card.ts +104 -104
  81. package/src/parse/parse_card/parse_mcq_card.ts +114 -114
  82. package/src/parse/parse_card_response.ts +197 -197
  83. package/src/parse/parse_source_content.ts +212 -212
  84. package/src/services/get_prompts.ts +164 -112
  85. package/src/services/open_ai_service.ts +89 -89
  86. package/src/services/qdrant_service.ts +10 -10
  87. package/src/types/base_param_type.ts +13 -13
  88. package/src/types/mongo_concept_fact_type.ts +12 -12
  89. package/src/types/parsed_card_type.ts +39 -39
  90. package/src/types/raw_card_response_types/generated_card_response_type.ts +59 -59
  91. package/src/types/source_taxonomy_type.ts +24 -24
  92. package/src/typology-parsed-response.ts +1932 -1932
  93. package/src/typology_gen/generate_concept_facts.ts +180 -169
  94. package/src/typology_gen/generate_typology.ts +203 -189
  95. package/src/typology_gen/summarize.ts +176 -164
  96. package/src/utils/distributed_quote_restoration.ts +80 -80
  97. package/src/utils/generate_args.ts +29 -29
  98. package/src/utils/parse_openai_response.ts +19 -19
  99. package/src/utils/sanitize_strings.ts +65 -65
  100. package/tsconfig.json +16 -16
  101. package/dist/constants/default_generation_variables.d.ts +0 -3
  102. package/dist/constants/default_generation_variables.d.ts.map +0 -1
  103. package/dist/constants/default_generation_variables.js +0 -580
  104. package/dist/constants/default_generation_variables.js.map +0 -1
  105. package/dist/services/prompts_test.d.ts +0 -10
  106. package/dist/services/prompts_test.d.ts.map +0 -1
  107. package/dist/services/prompts_test.js +0 -227
  108. package/dist/services/prompts_test.js.map +0 -1
  109. package/dist/types/generation_variables_schema.d.ts +0 -14
  110. package/dist/types/generation_variables_schema.d.ts.map +0 -1
  111. package/dist/types/generation_variables_schema.js +0 -3
  112. package/dist/types/generation_variables_schema.js.map +0 -1
  113. package/dist/utils/test.d.ts +0 -2
  114. package/dist/utils/test.d.ts.map +0 -1
  115. package/dist/utils/test.js +0 -5
  116. package/dist/utils/test.js.map +0 -1
  117. package/src/constants/default_generation_variables.ts +0 -624
  118. package/src/types/generation_variables_schema.ts +0 -16
@@ -1,50 +1,50 @@
1
- function isEmpty(obj: object): boolean {
2
- return Object.keys(obj).length === 0;
3
- }
4
-
5
- export function gapFilling(typologyResponse: any, cardgenResponse: any) {
6
- let allConcepts: string[] = [];
7
- let allFacts: string[] = [];
8
- let generatedConceptsList: string[] = [];
9
- let generatedFactsList: string[] = [];
10
- let remainingConcepts: string[] = [];
11
- let remainingFacts: string[] = [];
12
- if (!isEmpty(typologyResponse)) {
13
- allConcepts.push(...(typologyResponse.concepts ?? []));
14
- allFacts.push(...(typologyResponse?.facts ?? []));
15
- }
16
-
17
- if (!isEmpty(cardgenResponse)) {
18
- allConcepts.push(...(cardgenResponse.missing_concepts ?? []));
19
- allFacts.push(...(cardgenResponse.missing_facts ?? []));
20
- }
21
-
22
- if (
23
- cardgenResponse.cards_data !== undefined &&
24
- cardgenResponse.cards_data?.length != 0
25
- ) {
26
- for (let card of cardgenResponse.cards_data) {
27
- if (card.concepts.length != 0) {
28
- generatedConceptsList.push(...card.concepts);
29
- }
30
- if (card.facts.length != 0) {
31
- generatedFactsList.push(...card.facts);
32
- }
33
- }
34
-
35
- let generatedConceptsSet = Array.from(new Set(generatedConceptsList));
36
- let generatedFactsSet = Array.from(new Set(generatedFactsList));
37
-
38
- remainingConcepts = allConcepts.filter(
39
- (item) => !generatedConceptsSet.includes(item)
40
- );
41
- remainingFacts = allFacts.filter(
42
- (item) => !generatedFactsSet.includes(item)
43
- );
44
- }
45
-
46
- return {
47
- remainingConcepts: remainingConcepts,
48
- remainingFacts: remainingFacts,
49
- };
50
- }
1
+ function isEmpty(obj: object): boolean {
2
+ return Object.keys(obj).length === 0;
3
+ }
4
+
5
+ export function gapFilling(typologyResponse: any, cardgenResponse: any) {
6
+ let allConcepts: string[] = [];
7
+ let allFacts: string[] = [];
8
+ let generatedConceptsList: string[] = [];
9
+ let generatedFactsList: string[] = [];
10
+ let remainingConcepts: string[] = [];
11
+ let remainingFacts: string[] = [];
12
+ if (!isEmpty(typologyResponse)) {
13
+ allConcepts.push(...(typologyResponse.concepts ?? []));
14
+ allFacts.push(...(typologyResponse?.facts ?? []));
15
+ }
16
+
17
+ if (!isEmpty(cardgenResponse)) {
18
+ allConcepts.push(...(cardgenResponse.missing_concepts ?? []));
19
+ allFacts.push(...(cardgenResponse.missing_facts ?? []));
20
+ }
21
+
22
+ if (
23
+ cardgenResponse.cards_data !== undefined &&
24
+ cardgenResponse.cards_data?.length != 0
25
+ ) {
26
+ for (let card of cardgenResponse.cards_data) {
27
+ if (card.concepts.length != 0) {
28
+ generatedConceptsList.push(...card.concepts);
29
+ }
30
+ if (card.facts.length != 0) {
31
+ generatedFactsList.push(...card.facts);
32
+ }
33
+ }
34
+
35
+ let generatedConceptsSet = Array.from(new Set(generatedConceptsList));
36
+ let generatedFactsSet = Array.from(new Set(generatedFactsList));
37
+
38
+ remainingConcepts = allConcepts.filter(
39
+ (item) => !generatedConceptsSet.includes(item)
40
+ );
41
+ remainingFacts = allFacts.filter(
42
+ (item) => !generatedFactsSet.includes(item)
43
+ );
44
+ }
45
+
46
+ return {
47
+ remainingConcepts: remainingConcepts,
48
+ remainingFacts: remainingFacts,
49
+ };
50
+ }
@@ -1,33 +1,33 @@
1
- import { setUpMongoClient } from "./mongo_helper";
2
-
3
- export const getIdsForTitles = async (titles: string[]) => {
4
- try {
5
- const database = await setUpMongoClient();
6
- const collection = database.collection("_source");
7
- const rows = await collection
8
- .find({
9
- $or: [{ title: { $in: titles } }, { slug: { $in: titles } }],
10
- })
11
- .project({ _id: 1, title: 1, slug: 1 })
12
- .toArray();
13
-
14
- // Create a map of matched titles/slugs to their _ids
15
- const matchedMap = new Map();
16
- rows.forEach((row: any) => {
17
- if (row.title) matchedMap.set(row.title, row._id);
18
- if (row.slug) matchedMap.set(row.slug, row._id);
19
- });
20
-
21
- // Return result for every title in the input array
22
-
23
- return titles.map((title) => {
24
- const id = matchedMap.get(title);
25
- return {
26
- title,
27
- id: id ? id.toString() : null,
28
- };
29
- });
30
- } catch (error) {
31
- return [];
32
- }
33
- };
1
+ import { setUpMongoClient } from "./mongo_helper";
2
+
3
+ export const getIdsForTitles = async (titles: string[]) => {
4
+ try {
5
+ const database = await setUpMongoClient();
6
+ const collection = database.collection("_source");
7
+ const rows = await collection
8
+ .find({
9
+ $or: [{ title: { $in: titles } }, { slug: { $in: titles } }],
10
+ })
11
+ .project({ _id: 1, title: 1, slug: 1 })
12
+ .toArray();
13
+
14
+ // Create a map of matched titles/slugs to their _ids
15
+ const matchedMap = new Map();
16
+ rows.forEach((row: any) => {
17
+ if (row.title) matchedMap.set(row.title, row._id);
18
+ if (row.slug) matchedMap.set(row.slug, row._id);
19
+ });
20
+
21
+ // Return result for every title in the input array
22
+
23
+ return titles.map((title) => {
24
+ const id = matchedMap.get(title);
25
+ return {
26
+ title,
27
+ id: id ? id.toString() : null,
28
+ };
29
+ });
30
+ } catch (error) {
31
+ return [];
32
+ }
33
+ };
@@ -1,29 +1,29 @@
1
- import { Db, MongoClient, ObjectId } from "mongodb";
2
- import config from "../config";
3
-
4
- // One client per Lambda container (module scope)
5
- const localClient = new MongoClient(config.dbUri, {
6
- maxPoolSize: 30, // tune (20–50 typical for Lambda)
7
- minPoolSize: 0, // don't pin idle sockets
8
- maxConnecting: 3, // avoid handshake dogpile
9
- waitQueueTimeoutMS: 5000, // backpressure instead of pileups
10
- maxIdleTimeMS: 90_000, // drop idle to save ports
11
- serverSelectionTimeoutMS: 5000,
12
- connectTimeoutMS: 5000,
13
- retryWrites: true,
14
- });
15
-
16
- let client: MongoClient;
17
- async function setUpMongoClient(): Promise<Db> {
18
- if (!client) client = localClient;
19
-
20
- return client.db(config.dbName);
21
- }
22
-
23
- // export function setUpMongoClient(dbUrl: string, dbName: string) {
24
- // mongoClient = new MongoClient(dbUrl, {});
25
- // db = mongoClient.db(dbName);
26
- // // return { mongoClient, db };
27
- // }
28
-
29
- export { setUpMongoClient, ObjectId };
1
+ import { Db, MongoClient, ObjectId } from "mongodb";
2
+ import config from "../config";
3
+
4
+ // One client per Lambda container (module scope)
5
+ const localClient = new MongoClient(config.dbUri, {
6
+ maxPoolSize: 30, // tune (20–50 typical for Lambda)
7
+ minPoolSize: 0, // don't pin idle sockets
8
+ maxConnecting: 3, // avoid handshake dogpile
9
+ waitQueueTimeoutMS: 5000, // backpressure instead of pileups
10
+ maxIdleTimeMS: 90_000, // drop idle to save ports
11
+ serverSelectionTimeoutMS: 5000,
12
+ connectTimeoutMS: 5000,
13
+ retryWrites: true,
14
+ });
15
+
16
+ let client: MongoClient;
17
+ async function setUpMongoClient(): Promise<Db> {
18
+ if (!client) client = localClient;
19
+
20
+ return client.db(config.dbName);
21
+ }
22
+
23
+ // export function setUpMongoClient(dbUrl: string, dbName: string) {
24
+ // mongoClient = new MongoClient(dbUrl, {});
25
+ // db = mongoClient.db(dbName);
26
+ // // return { mongoClient, db };
27
+ // }
28
+
29
+ export { setUpMongoClient, ObjectId };
@@ -1,20 +1,20 @@
1
- import OpenAI from "openai";
2
-
3
- export class OpenAIHelper {
4
- public openAI: OpenAI;
5
- public openAIKey: string;
6
- constructor(openAIKey: string) {
7
- this.openAI = getOpenAI(openAIKey);
8
- this.openAIKey = openAIKey;
9
- }
10
- }
11
-
12
- const getOpenAI = (openAIKey: string) => {
13
- const openai = new OpenAI({
14
- apiKey: openAIKey,
15
- });
16
-
17
- return openai;
18
- };
19
-
20
- export { getOpenAI, OpenAI };
1
+ import OpenAI from "openai";
2
+
3
+ export class OpenAIHelper {
4
+ public openAI: OpenAI;
5
+ public openAIKey: string;
6
+ constructor(openAIKey: string) {
7
+ this.openAI = getOpenAI(openAIKey);
8
+ this.openAIKey = openAIKey;
9
+ }
10
+ }
11
+
12
+ const getOpenAI = (openAIKey: string) => {
13
+ const openai = new OpenAI({
14
+ apiKey: openAIKey,
15
+ });
16
+
17
+ return openai;
18
+ };
19
+
20
+ export { getOpenAI, OpenAI };
@@ -1,77 +1,77 @@
1
- import qdrantClient from "../services/qdrant_service";
2
-
3
- const createCollection = async (collectionName: string) => {
4
- await qdrantClient.createCollection(collectionName, {
5
- vectors: {
6
- size: 1536,
7
- distance: "Cosine",
8
- },
9
- });
10
- };
11
-
12
- const getCollection = async () => {
13
- const collection = await qdrantClient.getCollections();
14
- return collection;
15
- };
16
-
17
- const getCorrespondingConcepts = async (
18
- collectionName: string,
19
- embeddings: {
20
- text: string;
21
- id: string;
22
- type: string;
23
- reference: string;
24
- embedding: number[];
25
- }[],
26
- threshold: number
27
- ) => {
28
- try {
29
- const searchQuery = embeddings.map((e) => {
30
- return {
31
- query: e.embedding,
32
- limit: 1,
33
- score_threshold: threshold,
34
- with_payload: true,
35
- };
36
- });
37
- const results = await qdrantClient.queryBatch(collectionName, {
38
- searches: searchQuery,
39
- });
40
- return results;
41
- } catch (error) {
42
- console.log(error);
43
- throw error;
44
- }
45
- };
46
-
47
- const addEmbeddingsToCollection = async (
48
- collectionName: string,
49
- embeddings: {
50
- id: string;
51
- vector: number[];
52
- payload: {
53
- _sources: string[];
54
- text: string;
55
- };
56
- }[]
57
- ) => {
58
- const CHUNK_SIZE = 1000;
59
- for (let i = 0; i < embeddings.length; i += CHUNK_SIZE) {
60
- const batch = embeddings.slice(i, i + CHUNK_SIZE);
61
- await qdrantClient.upsert(
62
- collectionName,
63
-
64
- {
65
- wait: true,
66
- points: batch,
67
- }
68
- );
69
- }
70
- };
71
-
72
- export {
73
- createCollection,
74
- getCollection,
75
- addEmbeddingsToCollection,
76
- getCorrespondingConcepts as getSimilarConcepts,
77
- };
1
+ import qdrantClient from "../services/qdrant_service";
2
+
3
+ const createCollection = async (collectionName: string) => {
4
+ await qdrantClient.createCollection(collectionName, {
5
+ vectors: {
6
+ size: 1536,
7
+ distance: "Cosine",
8
+ },
9
+ });
10
+ };
11
+
12
+ const getCollection = async () => {
13
+ const collection = await qdrantClient.getCollections();
14
+ return collection;
15
+ };
16
+
17
+ const getCorrespondingConcepts = async (
18
+ collectionName: string,
19
+ embeddings: {
20
+ text: string;
21
+ id: string;
22
+ type: string;
23
+ reference: string;
24
+ embedding: number[];
25
+ }[],
26
+ threshold: number
27
+ ) => {
28
+ try {
29
+ const searchQuery = embeddings.map((e) => {
30
+ return {
31
+ query: e.embedding,
32
+ limit: 1,
33
+ score_threshold: threshold,
34
+ with_payload: true,
35
+ };
36
+ });
37
+ const results = await qdrantClient.queryBatch(collectionName, {
38
+ searches: searchQuery,
39
+ });
40
+ return results;
41
+ } catch (error) {
42
+ console.log(error);
43
+ throw error;
44
+ }
45
+ };
46
+
47
+ const addEmbeddingsToCollection = async (
48
+ collectionName: string,
49
+ embeddings: {
50
+ id: string;
51
+ vector: number[];
52
+ payload: {
53
+ _sources: string[];
54
+ text: string;
55
+ };
56
+ }[]
57
+ ) => {
58
+ const CHUNK_SIZE = 1000;
59
+ for (let i = 0; i < embeddings.length; i += CHUNK_SIZE) {
60
+ const batch = embeddings.slice(i, i + CHUNK_SIZE);
61
+ await qdrantClient.upsert(
62
+ collectionName,
63
+
64
+ {
65
+ wait: true,
66
+ points: batch,
67
+ }
68
+ );
69
+ }
70
+ };
71
+
72
+ export {
73
+ createCollection,
74
+ getCollection,
75
+ addEmbeddingsToCollection,
76
+ getCorrespondingConcepts as getSimilarConcepts,
77
+ };
@@ -1,98 +1,74 @@
1
- import { sanitizeStringsForSchema } from "../../utils/sanitize_strings";
2
-
3
- /**
4
- * Builds card output schema by populating the integrated schemas with concepts, facts, and card-specific schemas
5
- * @param concepts - Array of concept strings
6
- * @param facts - Array of fact strings
7
- * @param card_generation_types - Array of card types to generate (e.g., ["flash", "mcq", "cloze"])
8
- * @param cardTypeSchemas - Object mapping card types to their integrated schemas from getPrompts (e.g., { flash: {...}, mcq: {...} })
9
- * @returns Populated schema object ready for use
10
- */
11
- export const buildCardSchema = async (
12
- concepts: string[],
13
- facts: string[],
14
- card_generation_types: string[],
15
- cardTypeSchemas: Record<string, any>
16
- ) => {
17
- if (!cardTypeSchemas || Object.keys(cardTypeSchemas).length === 0) {
18
- throw new Error("Card type schemas are required");
19
- }
20
-
21
- const conceptsSanitized = sanitizeStringsForSchema(concepts);
22
- const factsSanitized = sanitizeStringsForSchema(facts);
23
-
24
- // Use the first available card type schema as the base (all have the same base structure)
25
- const firstCardType = card_generation_types.find(
26
- (type) => cardTypeSchemas[type]
27
- );
28
- if (!firstCardType) {
29
- throw new Error("No valid card type schema found");
30
- }
31
-
32
- // Deep clone to avoid mutating the original
33
- const populatedSchema = JSON.parse(
34
- JSON.stringify(cardTypeSchemas[firstCardType].schema)
35
- );
36
-
37
- // Populate concepts enum
38
- if (
39
- populatedSchema.schema?.properties?.test_cards?.items?.properties?.concepts
40
- ?.items?.enum
41
- ) {
42
- populatedSchema.schema.properties.test_cards.items.properties.concepts.items.enum =
43
- conceptsSanitized;
44
- }
45
-
46
- // Populate facts enum
47
- if (
48
- populatedSchema.schema?.properties?.test_cards?.items?.properties?.facts
49
- ?.items?.enum
50
- ) {
51
- populatedSchema.schema.properties.test_cards.items.properties.facts.items.enum =
52
- factsSanitized;
53
- }
54
-
55
- // Replace the type enum with the requested card generation types
56
- if (
57
- populatedSchema.schema?.properties?.test_cards?.items?.properties?.type
58
- ?.enum
59
- ) {
60
- populatedSchema.schema.properties.test_cards.items.properties.type.enum =
61
- card_generation_types;
62
- }
63
-
64
- // Extract card-specific schemas from the anyOf of each card type schema
65
- const filteredCardTypeSchemas: any[] = [];
66
- for (const cardType of card_generation_types) {
67
- if (cardTypeSchemas[cardType]) {
68
- const cardSchema = cardTypeSchemas[cardType];
69
- // Extract the card-specific schema from the anyOf array
70
- const cardContentSchema =
71
- cardSchema.schema?.properties?.test_cards?.items?.properties
72
- ?.card_content?.anyOf?.[0];
73
- if (cardContentSchema) {
74
- filteredCardTypeSchemas.push(cardContentSchema);
75
- }
76
- }
77
- }
78
-
79
- // Replace anyOf array with all card-specific schemas
80
- if (filteredCardTypeSchemas.length > 0) {
81
- if (
82
- populatedSchema.schema?.properties?.test_cards?.items?.properties
83
- ?.card_content
84
- ) {
85
- populatedSchema.schema.properties.test_cards.items.properties.card_content =
86
- {
87
- anyOf: filteredCardTypeSchemas,
88
- };
89
- }
90
- }
91
-
92
- console.log(
93
- "Populated Schema",
94
- JSON.stringify(populatedSchema.schema.properties.test_cards.items, null, 2)
95
- );
96
-
97
- return populatedSchema;
98
- };
1
+ import { sanitizeStringsForSchema } from "../../utils/sanitize_strings";
2
+ import { setUpMongoClient, ObjectId } from "../mongo_helper";
3
+
4
+ // flash:68ef4e1b5a123c94a835c6ab
5
+ // cloze:68ef4eb45a123c94a835c6ac
6
+ // mcq:68ef4f095a123c94a835c6ad
7
+ // match:68ef4fae5a123c94a835c6ae
8
+ export const buildCardSchema = async (
9
+ concepts: string[],
10
+ facts: string[],
11
+ card_generation_types: string[]
12
+ ) => {
13
+ const database = await setUpMongoClient();
14
+ const objectId = new ObjectId("689c5cbd0d9d3bbda64b9584");
15
+ const schemaObj = await database.collection("_prompts").findOne({
16
+ _id: objectId,
17
+ });
18
+ if (!schemaObj) {
19
+ throw new Error("Schema not found");
20
+ }
21
+ const schema = schemaObj.schema;
22
+ if (!schema) {
23
+ throw new Error("Schema not found");
24
+ }
25
+ const conceptsSanitized = sanitizeStringsForSchema(concepts);
26
+ const factsSanitized = sanitizeStringsForSchema(facts);
27
+
28
+ // Fetch individual card type schemas based on card_generation_types
29
+ const cardTypeObjectIds: { [key: string]: ObjectId } = {
30
+ flash: new ObjectId("68ef4e1b5a123c94a835c6ab"),
31
+ cloze: new ObjectId("68ef4eb45a123c94a835c6ac"),
32
+ mcq: new ObjectId("68ef4f095a123c94a835c6ad"),
33
+ match: new ObjectId("68ef4fae5a123c94a835c6ae"),
34
+ };
35
+
36
+ const cardTypeSchemas: { [key: string]: any } = {};
37
+
38
+ // Only fetch schemas for the requested card types
39
+ for (const cardType of card_generation_types) {
40
+ if (cardTypeObjectIds[cardType]) {
41
+ const cardSchemaObj = await database.collection("_prompts").findOne({
42
+ _id: cardTypeObjectIds[cardType],
43
+ });
44
+ if (cardSchemaObj && cardSchemaObj.schema) {
45
+ cardTypeSchemas[cardType] = JSON.parse(cardSchemaObj.schema);
46
+ }
47
+ }
48
+ }
49
+
50
+ // Deep clone to avoid mutating the original
51
+ const populatedSchema = JSON.parse(schema);
52
+ populatedSchema.schema.properties.test_cards.items.properties.concepts.items.enum =
53
+ conceptsSanitized;
54
+ populatedSchema.schema.properties.test_cards.items.properties.facts.items.enum =
55
+ factsSanitized;
56
+
57
+ // Replace the type enum with the requested card generation types
58
+ populatedSchema.schema.properties.test_cards.items.properties.type.enum =
59
+ card_generation_types;
60
+
61
+ // Replace anyOf array with individual schemas based on card type
62
+ if (Object.keys(cardTypeSchemas).length > 0) {
63
+ populatedSchema.schema.properties.test_cards.items.properties.card_content =
64
+ {
65
+ anyOf: Object.values(cardTypeSchemas),
66
+ };
67
+ }
68
+
69
+ console.log(
70
+ "Populated Schema",
71
+ JSON.stringify(populatedSchema.schema.properties.test_cards.items, null, 2)
72
+ );
73
+ return populatedSchema;
74
+ };