@learnpack/learnpack 5.0.148 → 5.0.152

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.
@@ -1,418 +1,62 @@
1
+ import toast from "react-hot-toast"
1
2
  import { RIGOBOT_HOST } from "./constants"
2
- import axios from "axios"
3
- import frontMatter from "front-matter"
4
- import { syllable } from "syllable"
5
-
6
- import * as yaml from "js-yaml"
3
+ import axios, { AxiosError } from "axios"
7
4
 
8
5
  type TInteractiveCreationInputs = {
9
6
  courseInfo: string
10
7
  prevInteractions: string
11
8
  }
9
+
12
10
  export const interactiveCreation = async (
13
- // token: string,
14
11
  inputs: TInteractiveCreationInputs
15
- ) => {
16
- const response = await axios.post(
17
- `${RIGOBOT_HOST}/v1/prompting/public/completion/390/`,
18
- {
19
- inputs: inputs,
20
- include_purpose_objective: false,
21
- execute_async: false,
22
- },
23
- {
24
- headers: {
25
- "Content-Type": "application/json",
26
- // Authorization: "Token " + token,
27
- },
28
- }
29
- )
30
-
31
- return response.data
32
- }
33
-
34
- type TCreateReadmeInputs = {
35
- title: string
36
- output_lang: string
37
- list_of_exercises: string
38
- tutorial_description: string
39
- include_quiz: string
40
- lesson_description: string
41
- }
42
-
43
- export const createReadme = async (
44
- token: string,
45
- inputs: TCreateReadmeInputs
46
- ) => {
12
+ ): Promise<any | null> => {
47
13
  try {
48
14
  const response = await axios.post(
49
- `${RIGOBOT_HOST}/v1/prompting/completion/423/`,
15
+ `${RIGOBOT_HOST}/v1/prompting/public/completion/390/`,
50
16
  {
51
- inputs,
17
+ inputs: inputs,
52
18
  include_purpose_objective: false,
53
19
  execute_async: false,
54
20
  },
55
21
  {
56
22
  headers: {
57
23
  "Content-Type": "application/json",
58
- Authorization: "Token " + token,
59
24
  },
60
25
  }
61
26
  )
62
- return response.data
63
- } catch (error) {
64
- console.error(error)
65
- return null
66
- }
67
- }
68
-
69
- type TCreateCodingReadmeInputs = {
70
- tutorial_description: string
71
- list_of_exercises: string
72
- output_lang: string
73
- title: string
74
- lesson_description: string
75
- }
76
- export const createCodingReadme = async (
77
- token: string,
78
- inputs: TCreateCodingReadmeInputs
79
- ) => {
80
- const response = await axios.post(
81
- `${RIGOBOT_HOST}/v1/prompting/completion/489/`,
82
- { inputs, include_purpose_objective: false, execute_async: false },
83
- {
84
- headers: {
85
- "Content-Type": "application/json",
86
- Authorization: "Token " + token,
87
- },
88
- }
89
- )
90
-
91
- return response.data
92
- }
93
-
94
- type TReadmeCreatorInputs = {
95
- tutorial_description: string
96
- list_of_exercises: string
97
- output_lang: string
98
- title: string
99
- lesson_description: string
100
- kind: string
101
- }
102
-
103
- export const readmeCreator = async (
104
- token: string,
105
- inputs: TReadmeCreatorInputs
106
- ) => {
107
- if (inputs.kind === "quiz" || inputs.kind === "read") {
108
- const createReadmeInputs: TCreateReadmeInputs = {
109
- title: inputs.title,
110
- output_lang: inputs.output_lang,
111
- list_of_exercises: inputs.list_of_exercises,
112
- tutorial_description: inputs.tutorial_description,
113
- include_quiz: inputs.kind === "quiz" ? "true" : "false",
114
- lesson_description: inputs.lesson_description,
115
- }
116
- return createReadme(token, createReadmeInputs)
117
- }
118
27
 
119
- if (inputs.kind === "code") {
120
- return createCodingReadme(token, {
121
- title: inputs.title,
122
- output_lang: inputs.output_lang,
123
- list_of_exercises: inputs.list_of_exercises,
124
- tutorial_description: inputs.tutorial_description,
125
- lesson_description: inputs.lesson_description,
126
- })
127
- }
128
-
129
- throw new Error("Invalid kind of lesson")
130
- }
131
-
132
- type TEstimateReadingTimeReturns = {
133
- minutes: number
134
- words: number
135
- }
136
-
137
- export const estimateReadingTime = (
138
- text: string,
139
- wordsPerMinute = 150
140
- ): TEstimateReadingTimeReturns => {
141
- const words = text.trim().split(/\s+/).length
142
- const minutes = words / wordsPerMinute
28
+ return response.data
29
+ } catch (error: unknown) {
30
+ const err = error as AxiosError
143
31
 
144
- if (minutes < 1) {
145
- if (words === 0)
146
- return {
147
- minutes: 1,
148
- words,
149
- }
150
- } else {
151
- return {
152
- minutes,
153
- words,
32
+ if (err.response?.status === 403) {
33
+ toast.error("You've reached the limit. Please log in to continue.")
34
+ } else {
35
+ toast.error("Something went wrong while generating the course.")
154
36
  }
155
- }
156
37
 
157
- return {
158
- minutes: 1,
159
- words,
38
+ return null
160
39
  }
161
40
  }
162
41
 
163
- type TFKGLResult = {
164
- text: string
165
- fkgl: number
166
- }
167
-
168
- export function checkReadability(
169
- markdown: string,
170
- wordsPerMinute = 200,
171
- maxMinutes = 1
172
- ): {
173
- newMarkdown: string
174
- exceedsThreshold: boolean
175
- minutes: number
176
- body: string
177
- fkglResult: TFKGLResult
178
- // readingEase: number
179
- } {
180
- const parsed = frontMatter(markdown)
181
-
182
- const fkglResult = fleschKincaidGrade(parsed.body)
183
-
184
- const readingTime = estimateReadingTime(parsed.body, wordsPerMinute)
185
-
186
- // const readingEase = estimateReadingEase(parsed.body)
187
- let attributes = parsed.attributes ? parsed.attributes : {}
188
-
189
- if (typeof parsed.attributes !== "object") {
190
- attributes = {}
191
- }
192
-
193
- const updatedAttributes = {
194
- ...attributes,
195
- readingTime,
196
- fkglResult: fkglResult.fkgl,
197
- }
198
-
199
- let yamlFrontMatter = ""
42
+ export const isHuman = async (token: string) => {
200
43
  try {
201
- yamlFrontMatter = yaml.dump(updatedAttributes).trim()
202
- } catch {
203
- // Console.error("Error dumping YAML front matter")
204
- return {
205
- newMarkdown: "",
206
- exceedsThreshold: false,
207
- minutes: 0,
208
- body: "",
209
- fkglResult,
210
- // readingEase: 0,
44
+ const body = {
45
+ access_token: token,
211
46
  }
212
- }
213
-
214
- const newMarkdown = `---\n${yamlFrontMatter}\n---\n\n${parsed.body}`
215
-
216
- return {
217
- newMarkdown,
218
- exceedsThreshold: readingTime.minutes > maxMinutes,
219
- minutes: readingTime.minutes,
220
- body: parsed.body,
221
- fkglResult,
222
- }
223
- }
224
-
225
- export function extractImagesFromMarkdown(markdown: string) {
226
- const imageRegex = /!\[([^\]]*)]\(([^)]+)\)/g
227
- const images = []
228
- let match
229
-
230
- while ((match = imageRegex.exec(markdown)) !== null) {
231
- const altText = match[1]
232
- const url = match[2]
233
- images.push({ alt: altText, url: url })
234
- }
235
-
236
- return images
237
- }
238
-
239
- export function estimateDuration(listOfSteps: string[]): number {
240
- let duration = 0
241
-
242
- for (const step of listOfSteps) {
243
- if (step.includes("[READ:")) {
244
- duration += 2
245
- } else if (step.includes("[QUIZ:")) {
246
- duration += 3
247
- } else if (step.includes("[CODE:")) {
248
- duration += 5
249
- }
250
- }
251
-
252
- return duration
253
- }
254
-
255
- export function extractTextFromMarkdown(mdContent: string): string {
256
- return mdContent
257
- .replace(/!\[.*?]\(.*?\)/g, "") // Remove images
258
- .replace(/\[.*?]\(.*?\)/g, "") // Remove links
259
- .replace(/(```[\S\s]*?```|`.*?`)/g, "") // Remove inline & block code
260
- .replace(/^#.*$/gm, "") // Remove headings
261
- .replace(/(\*{1,2}|_{1,2})/g, "") // Remove bold/italic markers
262
- .replace(/>\s?/g, "") // Remove blockquotes
263
- .replace(/[*-]\s+/g, "") // Remove bullets from lists
264
- .trim()
265
- }
266
-
267
- /**
268
- * Splits a paragraph into words and separates each word into syllables.
269
- * @param paragraph The input paragraph.
270
- * @returns An array of words, each split into syllables.
271
- */
272
- export function splitIntoSyllables(paragraph: string): string[] {
273
- const words = paragraph.split(/\s+/)
274
- const syllables: string[] = []
275
-
276
- for (const word of words) {
277
- syllables.push(...splitWordIntoSyllables(word))
278
- }
279
-
280
- return syllables
281
- }
282
-
283
- /**
284
- * Splits a word into its syllables using a basic estimation.
285
- * @param word The word to split.
286
- * @returns An array of syllables.
287
- */
288
- export function splitWordIntoSyllables(word: string): string[] {
289
- const syllableCount = syllable(word)
290
-
291
- // Simple heuristic: Split word into equal parts (not perfect, better with a dictionary-based approach)
292
- if (syllableCount <= 1) return [word]
293
-
294
- const approxLength = Math.ceil(word.length / syllableCount)
295
- const syllables: string[] = []
296
- for (let i = 0; i < word.length; i += approxLength) {
297
- // eslint-disable-next-line
298
- syllables.push(word.substring(i, i + approxLength))
299
- }
300
-
301
- return syllables
302
- }
303
-
304
- /**
305
- * Extracts words from a given paragraph.
306
- * @param paragraph The input text.
307
- * @returns An array of words.
308
- */
309
- export function extractWords(paragraph: string): string[] {
310
- const words = paragraph.match(/\b\w+\b/g) // Match words using regex
311
- return words ? words : [] // Return words or an empty array if none found
312
- }
313
-
314
- /**
315
- * Calculates the Flesch-Kincaid Grade Level (FKGL) for a given text.
316
- * @param text The input paragraph.
317
- * @returns The FKGL score.
318
- */
319
- export function fleschKincaidGrade(text: string): TFKGLResult {
320
- const processableText = extractTextFromMarkdown(text)
321
- const words = extractWords(processableText)
322
- const numWords = words.length
323
- const numSentences = countSentences(processableText)
324
- const numSyllables = words.reduce((total, word) => total + syllable(word), 0)
325
-
326
- if (numWords === 0 || numSentences === 0) {
327
- return {
328
- text,
329
- fkgl: 0,
330
- }
331
- }
332
-
333
- const fkgl =
334
- // eslint-disable-next-line
335
- 0.39 * (numWords / numSentences) + 11.8 * (numSyllables / numWords) - 15.59
336
-
337
- return {
338
- text,
339
- fkgl: parseFloat(fkgl.toFixed(2)),
340
- }
341
- }
342
-
343
- /**
344
- * Counts the number of sentences in a given text.
345
- * @param text The input paragraph.
346
- * @returns The total number of sentences.
347
- */
348
- export function countSentences(text: string): number {
349
- const sentences = text
350
- .split(/[!.?]+/)
351
- .filter((sentence) => sentence.trim().length > 0)
352
- return sentences.length
353
- }
354
-
355
- export function howManyDifficultParagraphs(
356
- paragraphs: TFKGLResult[],
357
- maxFKGL: number
358
- ): number {
359
- return paragraphs.filter((paragraph) => paragraph.fkgl > maxFKGL).length
360
- }
361
-
362
- type TReduceReadmeInputs = {
363
- lesson: string
364
- number_of_words: string
365
- expected_number_words: string
366
- fkgl_results: string
367
- expected_grade_level: string
368
- }
369
- export async function makeReadmeReadable(
370
- rigoToken: string,
371
- inputs: TReduceReadmeInputs
372
- ) {
373
- try {
374
47
  const response = await axios.post(
375
- `${RIGOBOT_HOST}/v1/prompting/completion/588/`,
376
- { inputs, include_purpose_objective: false, execute_async: false },
48
+ `${RIGOBOT_HOST}/v1/auth/verify/humanity`,
49
+ body,
377
50
  {
378
51
  headers: {
379
52
  "Content-Type": "application/json",
380
- Authorization: "Token " + rigoToken,
381
53
  },
382
54
  }
383
55
  )
384
56
 
385
- return response.data
57
+ return response.status === 200
386
58
  } catch (error) {
387
59
  console.error(error)
388
- // Console.debug(error)
389
- return null
60
+ return false
390
61
  }
391
62
  }
392
-
393
- type TCreateCodeFileInputs = {
394
- readme: string
395
- tutorial_info: string
396
- }
397
-
398
- export const createCodeFile = async (
399
- token: string,
400
- inputs: TCreateCodeFileInputs
401
- ) => {
402
- const response = await axios.post(
403
- `${RIGOBOT_HOST}/v1/prompting/completion/456/`,
404
- {
405
- inputs: inputs,
406
- include_purpose_objective: false,
407
- execute_async: false,
408
- },
409
- {
410
- headers: {
411
- "Content-Type": "application/json",
412
- Authorization: "Token " + token,
413
- },
414
- }
415
- )
416
-
417
- return response.data
418
- }
@@ -395,9 +395,6 @@
395
395
  .top-2 {
396
396
  top: calc(var(--spacing) * 2);
397
397
  }
398
- .right-0 {
399
- right: calc(var(--spacing) * 0);
400
- }
401
398
  .right-2 {
402
399
  right: calc(var(--spacing) * 2);
403
400
  }
@@ -525,18 +522,12 @@
525
522
  .ml-auto {
526
523
  margin-left: auto;
527
524
  }
528
- .block {
529
- display: block;
530
- }
531
525
  .flex {
532
526
  display: flex;
533
527
  }
534
528
  .hidden {
535
529
  display: none;
536
530
  }
537
- .inline {
538
- display: inline;
539
- }
540
531
  .inline-block {
541
532
  display: inline-block;
542
533
  }
@@ -718,9 +709,6 @@
718
709
  .gap-3 {
719
710
  gap: calc(var(--spacing) * 3);
720
711
  }
721
- .gap-4 {
722
- gap: calc(var(--spacing) * 4);
723
- }
724
712
  :where(.space-y-2 > :not(:last-child)) {
725
713
  --tw-space-y-reverse: 0;
726
714
  margin-block-start: calc(