@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.
- package/README.md +12 -12
- package/lib/commands/audit.js +15 -15
- package/lib/commands/init.js +39 -15
- package/lib/commands/translate.js +2 -10
- package/lib/managers/server/routes.js +38 -0
- package/lib/utils/creatorUtilities.d.ts +2 -0
- package/lib/utils/creatorUtilities.js +48 -7
- package/lib/utils/rigoActions.d.ts +1 -0
- package/lib/utils/rigoActions.js +13 -2
- package/oclif.manifest.json +1 -1
- package/package.json +2 -1
- package/src/commands/audit.ts +449 -449
- package/src/commands/breakToken.ts +36 -36
- package/src/commands/init.ts +48 -17
- package/src/commands/publish.ts +312 -312
- package/src/commands/translate.ts +1 -20
- package/src/managers/config/index.ts +1 -0
- package/src/managers/server/routes.ts +61 -1
- package/src/utils/console.ts +24 -24
- package/src/utils/creatorUtilities.ts +66 -6
- package/src/utils/rigoActions.ts +13 -1
@@ -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 {
|
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,
|
package/src/utils/console.ts
CHANGED
@@ -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
|
-
|
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
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
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
|
+
}
|
package/src/utils/rigoActions.ts
CHANGED
@@ -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.
|
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
|
+
}
|