@learnpack/learnpack 5.0.30 → 5.0.31

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.
@@ -510,6 +510,7 @@ fs.mkdirSync(confPath.base)
510
510
  exercise(path, position, configObj)
511
511
  ) :
512
512
  [exercise(configObj?.config?.exercisesPath || "", 0, configObj)]
513
+
513
514
  this.save()
514
515
  },
515
516
  createExercise: (slug: string, content: string, language: string) => {
@@ -12,7 +12,9 @@ import { IConfigManager } from "../../models/config-manager"
12
12
  import { IExercise } from "../../models/exercise-obj"
13
13
  import SessionManager from "../../managers/session"
14
14
  import TelemetryManager from "../telemetry"
15
- import { eventManager } from "../../utils/osOperations"
15
+ import { saveTranslatedReadme } from "../../utils/creatorUtilities"
16
+ import { translateExercise } from "../../utils/rigoActions"
17
+ // import { eventManager } from "../../utils/osOperations"
16
18
 
17
19
  const withHandler =
18
20
  (func: (req: express.Request, res: express.Response) => void) =>
@@ -394,6 +396,64 @@ throw new Error("File not found: " + filePath)
394
396
  })
395
397
  )
396
398
 
399
+ app.post(
400
+ "/actions/translate",
401
+ jsonBodyParser,
402
+ withHandler(async (req: express.Request, res: express.Response) => {
403
+ const { exerciseSlugs, languages } = req.body
404
+
405
+ const session = await SessionManager.getPayload()
406
+ const rigoToken = session?.rigobot?.key
407
+
408
+ if (!rigoToken) {
409
+ return res.status(400).json({ error: "RigoToken not found" })
410
+ }
411
+
412
+ const languagesToTranslate: string[] = languages.split(",")
413
+
414
+ try {
415
+ await Promise.all(
416
+ exerciseSlugs.map(async (slug: string) => {
417
+ const exercise = configManager.getExercise(slug)
418
+ if (!exercise) {
419
+ throw new Error(`Exercise ${slug} not found`)
420
+ }
421
+
422
+ if (exercise.getReadme) {
423
+ const readme = exercise.getReadme(null)
424
+
425
+ await Promise.all(
426
+ languagesToTranslate.map(async (language: string) => {
427
+ const response = await translateExercise(rigoToken, {
428
+ text_to_translate: readme.body,
429
+ output_language: language,
430
+ })
431
+
432
+ await saveTranslatedReadme(
433
+ slug,
434
+ response.parsed.output_language_code,
435
+ response.parsed.translation
436
+ )
437
+
438
+ Console.success(
439
+ `Translated ${slug} to ${language} successfully`
440
+ )
441
+ })
442
+ )
443
+ }
444
+ })
445
+ )
446
+
447
+ configManager.buildIndex()
448
+
449
+ return res.status(200).json({ message: "Translated exercises" })
450
+ } catch (error) {
451
+ console.log(error, "ERROR")
452
+ return res.status(400).json({ error: (error as Error).message })
453
+ }
454
+ })
455
+ )
456
+
397
457
  app.post(
398
458
  "/exercise/:slug/create",
399
459
  jsonBodyParser,
@@ -1,24 +1,24 @@
1
- import * as chalk from "chalk"
2
-
3
- export default {
4
- // _debug: true,
5
- _debug: process.env.DEBUG === "true",
6
- startDebug: function () {
7
- this._debug = true
8
- },
9
- log: (msg: string | Array<string>, ...args: Array<any>) =>
10
- console.log(chalk.gray(msg), ...args),
11
- error: (msg: string, ...args: Array<any>) =>
12
- console.log(chalk.red("⨉ " + msg), ...args),
13
- success: (msg: string, ...args: Array<any>) =>
14
- console.log(chalk.green("✓ " + msg), ...args),
15
- info: (msg: any, ...args: Array<any>) =>
16
- console.log(chalk.blue("ⓘ " + msg), ...args),
17
- help: (msg: string) =>
18
- console.log(`${chalk.white.bold("⚠ help:")} ${chalk.white(msg)}`),
19
- debug(...args: Array<any>) {
20
- this._debug && console.log(chalk.magentaBright("⚠ debug: "), args)
21
- },
22
- warning: (msg: string) =>
23
- console.log(`${chalk.yellow("⚠ warning:")} ${chalk.yellow(msg)}`),
24
- }
1
+ import * as chalk from "chalk"
2
+
3
+ export default {
4
+ // _debug: true,
5
+ _debug: process.env.DEBUG === "true",
6
+ startDebug: function () {
7
+ this._debug = true
8
+ },
9
+ log: (msg: string | Array<string>, ...args: Array<any>) =>
10
+ console.log(chalk.gray(msg), ...args),
11
+ error: (msg: string, ...args: Array<any>) =>
12
+ console.log(chalk.red("⨉ " + msg), ...args),
13
+ success: (msg: string, ...args: Array<any>) =>
14
+ console.log(chalk.green("✓ " + msg), ...args),
15
+ info: (msg: any, ...args: Array<any>) =>
16
+ console.log(chalk.blue("ⓘ " + msg), ...args),
17
+ help: (msg: string) =>
18
+ console.log(`${chalk.white.bold("⚠ help:")} ${chalk.white(msg)}`),
19
+ debug(...args: Array<any>) {
20
+ this._debug && console.log(chalk.magentaBright("⚠ debug: "), args)
21
+ },
22
+ warning: (msg: string) =>
23
+ console.log(`${chalk.yellow("⚠ warning:")} ${chalk.yellow(msg)}`),
24
+ }
@@ -1,5 +1,6 @@
1
- // eslint-disable-next-line
1
+
2
2
  const frontMatter = require("front-matter")
3
+
3
4
  import * as path from "path"
4
5
  import * as fs from "fs"
5
6
  import { homedir } from "os"
@@ -61,11 +62,13 @@ export function checkReadingTime(
61
62
  exceedsThreshold: boolean
62
63
  minutes: number
63
64
  body: string
65
+ // readingEase: number
64
66
  } {
65
67
  const parsed = frontMatter(markdown)
66
68
 
67
69
  const readingTime = estimateReadingTime(parsed.body, wordsPerMinute)
68
70
 
71
+ // const readingEase = estimateReadingEase(parsed.body)
69
72
  let attributes = parsed.attributes ? parsed.attributes : {}
70
73
 
71
74
  if (typeof parsed.attributes !== "object") {
@@ -75,6 +78,7 @@ export function checkReadingTime(
75
78
  const updatedAttributes = {
76
79
  ...attributes,
77
80
  readingTime,
81
+ // readingEase,
78
82
  }
79
83
 
80
84
  let yamlFrontMatter = ""
@@ -86,6 +90,7 @@ export function checkReadingTime(
86
90
  exceedsThreshold: false,
87
91
  minutes: 0,
88
92
  body: "",
93
+ // readingEase: 0,
89
94
  }
90
95
  }
91
96
 
@@ -97,6 +102,7 @@ export function checkReadingTime(
97
102
  exceedsThreshold: readingTime.minutes > maxMinutes,
98
103
  minutes: readingTime.minutes,
99
104
  body: parsed.body,
105
+ // readingEase: 0,
100
106
  }
101
107
  }
102
108
 
@@ -189,11 +195,13 @@ export function estimateDuration(listOfSteps: string[]): number {
189
195
  const writeFilePromise = promisify(fs.writeFile)
190
196
  const execPromise = promisify(exec)
191
197
 
192
- const example_content = `
193
- 00.1 - Introduction to AI [READ: Small introduction to important concepts such as AI, machine learning, and their applications]
194
- 01.1 - Introduction to Machine Learning [READ: Small introduction to important concepts such as AI, machine learning, and their applications]
195
- 01.2 - Introduction to Deep Learning [QUIZ: Small introduction to important concepts such as AI, machine learning, and their applications]
196
- 02.1 - Test your knowledge [CODE: Code problem to solve]
198
+ const example_content = `Write or paste your table of content below this line, each topic should be defined on a new line, here is an example:
199
+
200
+ Introduction to AI: Explain what is AI and its applications
201
+ Introduction to Machine Learning: Explain what is machine learning and its applications
202
+ What is an AI Model: Explain what is an AI model and its applications
203
+ How to use an AI Model: Different APIs, local models, etc.
204
+ How to build an AI Model: Fine-tuning, data collection, cleaning and more.
197
205
  `
198
206
 
199
207
  export async function createFileOnDesktop() {
@@ -239,3 +247,55 @@ export function getContentIndex() {
239
247
  const content = fs.readFileSync(filePath, "utf8")
240
248
  return content
241
249
  }
250
+
251
+ // export function fleschKincaidReadingEase(text: string): number {
252
+ // const sentences = text.split(/[.!?]/).filter((s) => s.trim().length > 0)
253
+ // const words = text.split(/\s+/).filter((w) => w.trim().length > 0)
254
+ // const totalSyllables = words.reduce((sum, word) => sum + syllable(word), 0)
255
+
256
+ // const ASL = words.length / sentences.length // Average Sentence Length
257
+ // const ASW = totalSyllables / words.length // Average Syllables per Word
258
+
259
+ // return Math.round(206.835 - 1.015 * ASL - 84.6 * ASW)
260
+ // }
261
+
262
+ export function extractTextFromMarkdown(mdContent: string): string {
263
+ let content = mdContent.replace(/!\[.*?]\(.*?\)/g, "")
264
+ content = content.replace(/\[.*?]\(.*?\)/g, "")
265
+ content = content.replace(/`.*?`/g, "")
266
+ content = content.replace(/```[\S\s]*?```/g, "")
267
+
268
+ return content.trim()
269
+ }
270
+
271
+ // export const estimateReadingEase = async (text: string): Promise<number> => {
272
+ // const cleanedText = extractTextFromMarkdown(text)
273
+ // // @ts-ignore
274
+ // const rs = (await import("text-readability")).default;
275
+ // // return fleschKincaidReadingEase(cleanedText)
276
+ // // const score = readability(cleanedText)
277
+ // // console.log(score)
278
+ // // return score.fleschKincaid ?? 0
279
+ // const score = rs.fleschReadingEase(cleanedText)
280
+ // console.log(score, "SCORE FLESCH READING EASE")
281
+ // return score
282
+ // }
283
+
284
+ const cleanReadme = (readme: string) => {
285
+ // Replace <text> and </text> with nothing
286
+ return readme.replace(/<text>/g, "").replace(/<\/text>/g, "")
287
+ }
288
+
289
+ export const saveTranslatedReadme = async (
290
+ exercise: string,
291
+ languageCode: string,
292
+ readme: string
293
+ ) => {
294
+ const readmePath = path.join(
295
+ process.cwd(),
296
+ "exercises",
297
+ exercise,
298
+ `README.${languageCode}.md`
299
+ )
300
+ fs.writeFileSync(readmePath, cleanReadme(readme))
301
+ }
@@ -62,7 +62,7 @@ return false
62
62
  Console.debug("The user is a creator! 🎉")
63
63
  return true
64
64
  } catch (error) {
65
- Console.debug(error)
65
+ Console.error(error as string)
66
66
  return false
67
67
  }
68
68
  }
@@ -323,3 +323,15 @@ export async function reduceReadme(
323
323
  return null
324
324
  }
325
325
  }
326
+
327
+ export const isValidRigoToken = async (rigobotToken: string) => {
328
+ const rigoUrl = `${RIGOBOT_HOST}/v1/auth/token/${rigobotToken}`
329
+ const rigoResp = await fetch(rigoUrl)
330
+ if (!rigoResp.ok) {
331
+ Console.debug("Invalid Rigobot token", rigoResp.status)
332
+ Console.debug(rigoResp.statusText)
333
+ return false
334
+ }
335
+
336
+ return true
337
+ }