@learnpack/learnpack 5.0.274 → 5.0.275
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 +409 -409
- package/lib/commands/audit.js +15 -15
- package/lib/commands/breakToken.js +19 -19
- package/lib/commands/clean.js +3 -3
- package/lib/commands/init.js +41 -41
- package/lib/commands/logout.js +3 -3
- package/lib/commands/serve.js +127 -70
- package/lib/creatorDist/assets/index-BfLyIQVh.js +10223 -10342
- package/lib/managers/config/index.js +77 -77
- package/lib/models/creator.d.ts +7 -0
- package/lib/utils/api.d.ts +1 -0
- package/lib/utils/api.js +2 -1
- package/lib/utils/creatorUtilities.js +14 -14
- package/package.json +1 -1
- package/src/commands/audit.ts +487 -487
- package/src/commands/breakToken.ts +67 -67
- package/src/commands/clean.ts +30 -30
- package/src/commands/init.ts +650 -650
- package/src/commands/logout.ts +38 -38
- package/src/commands/publish.ts +522 -522
- package/src/commands/serve.ts +162 -107
- package/src/commands/start.ts +333 -333
- package/src/commands/translate.ts +123 -123
- package/src/creator/README.md +54 -54
- package/src/creator/eslint.config.js +28 -28
- package/src/creator/src/components/syllabus/ContentIndex.tsx +312 -312
- package/src/creator/src/i18n.ts +28 -28
- package/src/creator/src/index.css +217 -217
- package/src/creator/src/locales/en.json +126 -126
- package/src/creator/src/locales/es.json +126 -126
- package/src/creator/src/utils/configTypes.ts +122 -122
- package/src/creator/src/utils/constants.ts +13 -13
- package/src/creator/src/utils/creatorUtils.ts +46 -46
- package/src/creator/src/utils/eventBus.ts +2 -2
- package/src/creator/src/utils/lib.ts +468 -468
- package/src/creator/src/utils/socket.ts +61 -61
- package/src/creator/src/utils/store.ts +222 -222
- package/src/creator/src/vite-env.d.ts +1 -1
- package/src/creator/vite.config.ts +13 -13
- package/src/creatorDist/assets/index-BfLyIQVh.js +10223 -10342
- package/src/managers/config/defaults.ts +49 -49
- package/src/managers/config/exercise.ts +364 -364
- package/src/managers/config/index.ts +775 -775
- package/src/managers/file.ts +236 -236
- package/src/managers/server/routes.ts +554 -554
- package/src/managers/session.ts +182 -182
- package/src/managers/telemetry.ts +188 -188
- package/src/models/action.ts +13 -13
- package/src/models/config-manager.ts +28 -28
- package/src/models/config.ts +106 -106
- package/src/models/creator.ts +47 -40
- package/src/models/exercise-obj.ts +30 -30
- package/src/models/session.ts +39 -39
- package/src/models/socket.ts +61 -61
- package/src/models/status.ts +16 -16
- package/src/ui/_app/app.js +141 -141
- package/src/ui/app.tar.gz +0 -0
- package/src/utils/BaseCommand.ts +56 -56
- package/src/utils/api.ts +31 -30
- package/src/utils/audit.ts +392 -392
- package/src/utils/checkNotInstalled.ts +267 -267
- package/src/utils/configBuilder.ts +82 -82
- package/src/utils/convertCreds.js +34 -34
- package/src/utils/creatorUtilities.ts +504 -504
- package/src/utils/incrementVersion.js +74 -74
- package/src/utils/misc.ts +58 -58
- package/src/utils/rigoActions.ts +500 -500
- package/src/utils/sidebarGenerator.ts +195 -195
- package/src/utils/templates/isolated/exercises/01-hello-world/README.es.md +26 -26
- package/src/utils/templates/isolated/exercises/01-hello-world/README.md +26 -26
package/lib/commands/audit.js
CHANGED
@@ -369,21 +369,21 @@ class AuditCommand extends SessionCommand_1.default {
|
|
369
369
|
}
|
370
370
|
}
|
371
371
|
}
|
372
|
-
AuditCommand.description = `learnpack audit is the command in charge of creating an auditory of the repository
|
373
|
-
...
|
374
|
-
learnpack audit checks for the following information in a repository:
|
375
|
-
1. The configuration object has slug, repository and description. (Error)
|
376
|
-
2. The command learnpack clean has been run. (Error)
|
377
|
-
3. If a markdown or test file doesn't have any content. (Error)
|
378
|
-
4. The links are accessing to valid servers. (Error)
|
379
|
-
5. The relative images are working (If they have the shortest path to the image or if the images exists in the assets). (Error)
|
380
|
-
6. The external images are working (If they are pointing to a valid server). (Error)
|
381
|
-
7. The exercises directory names are valid. (Error)
|
382
|
-
8. If an exercise doesn't have a README file. (Error)
|
383
|
-
9. The exercises array (Of the config file) has content. (Error)
|
384
|
-
10. The exercses have the same translations. (Warning)
|
385
|
-
11. The .gitignore file exists. (Warning)
|
386
|
-
12. If there is a file within the exercises folder but not inside of any particular exercise's folder. (Warning)
|
372
|
+
AuditCommand.description = `learnpack audit is the command in charge of creating an auditory of the repository
|
373
|
+
...
|
374
|
+
learnpack audit checks for the following information in a repository:
|
375
|
+
1. The configuration object has slug, repository and description. (Error)
|
376
|
+
2. The command learnpack clean has been run. (Error)
|
377
|
+
3. If a markdown or test file doesn't have any content. (Error)
|
378
|
+
4. The links are accessing to valid servers. (Error)
|
379
|
+
5. The relative images are working (If they have the shortest path to the image or if the images exists in the assets). (Error)
|
380
|
+
6. The external images are working (If they are pointing to a valid server). (Error)
|
381
|
+
7. The exercises directory names are valid. (Error)
|
382
|
+
8. If an exercise doesn't have a README file. (Error)
|
383
|
+
9. The exercises array (Of the config file) has content. (Error)
|
384
|
+
10. The exercses have the same translations. (Warning)
|
385
|
+
11. The .gitignore file exists. (Warning)
|
386
|
+
12. If there is a file within the exercises folder but not inside of any particular exercise's folder. (Warning)
|
387
387
|
`;
|
388
388
|
AuditCommand.flags = {
|
389
389
|
strict: command_1.flags.boolean({
|
@@ -4,25 +4,25 @@ const command_1 = require("@oclif/command");
|
|
4
4
|
const BaseCommand_1 = require("../utils/BaseCommand");
|
5
5
|
const console_1 = require("../utils/console");
|
6
6
|
const creatorUtilities_1 = require("../utils/creatorUtilities");
|
7
|
-
const exampleMd = `# How to Install Node.js
|
8
|
-
|
9
|
-
Node.js lets you run JavaScript outside a web browser.
|
10
|
-
|
11
|
-
## Step 1: Download Node.js
|
12
|
-
|
13
|
-
Get the Node.js installer from the [official site](https://nodejs.org/en/download/).
|
14
|
-
|
15
|
-
## Step 2: Install Node.js
|
16
|
-
|
17
|
-
Open the installer and follow the steps to finish.
|
18
|
-
|
19
|
-
## Step 3: Verify the Installation
|
20
|
-
|
21
|
-
Open a terminal and type:
|
22
|
-
|
23
|
-
\`\`\`bash
|
24
|
-
node -v
|
25
|
-
\`\`\`
|
7
|
+
const exampleMd = `# How to Install Node.js
|
8
|
+
|
9
|
+
Node.js lets you run JavaScript outside a web browser.
|
10
|
+
|
11
|
+
## Step 1: Download Node.js
|
12
|
+
|
13
|
+
Get the Node.js installer from the [official site](https://nodejs.org/en/download/).
|
14
|
+
|
15
|
+
## Step 2: Install Node.js
|
16
|
+
|
17
|
+
Open the installer and follow the steps to finish.
|
18
|
+
|
19
|
+
## Step 3: Verify the Installation
|
20
|
+
|
21
|
+
Open a terminal and type:
|
22
|
+
|
23
|
+
\`\`\`bash
|
24
|
+
node -v
|
25
|
+
\`\`\`
|
26
26
|
`;
|
27
27
|
class BreakTokenCommand extends BaseCommand_1.default {
|
28
28
|
async run() {
|
package/lib/commands/clean.js
CHANGED
@@ -16,9 +16,9 @@ class CleanCommand extends SessionCommand_1.default {
|
|
16
16
|
console_1.default.success("Package cleaned successfully, ready to publish");
|
17
17
|
}
|
18
18
|
}
|
19
|
-
CleanCommand.description = `Clean the configuration object
|
20
|
-
...
|
21
|
-
Extra documentation goes here
|
19
|
+
CleanCommand.description = `Clean the configuration object
|
20
|
+
...
|
21
|
+
Extra documentation goes here
|
22
22
|
`;
|
23
23
|
CleanCommand.flags = {
|
24
24
|
// name: flags.string({char: 'n', description: 'name to print'}),
|
package/lib/commands/init.js
CHANGED
@@ -107,9 +107,9 @@ const initializeInteractiveCreation = async (rigoToken, courseInfo) => {
|
|
107
107
|
while (!isReady) {
|
108
108
|
const spinner = (0, ora_1.default)("Thinking...").start();
|
109
109
|
let wholeInfo = courseInfo;
|
110
|
-
wholeInfo += `
|
111
|
-
Current title: ${currentTitle}
|
112
|
-
Current description: ${currentDescription}
|
110
|
+
wholeInfo += `
|
111
|
+
Current title: ${currentTitle}
|
112
|
+
Current description: ${currentDescription}
|
113
113
|
`;
|
114
114
|
// eslint-disable-next-line
|
115
115
|
const res = await (0, rigoActions_1.interactiveCreation)(rigoToken, {
|
@@ -200,56 +200,56 @@ const handleAILogic = async (tutorialDir, packageInfo) => {
|
|
200
200
|
fs.mkdirSync(rulesDir, { recursive: true });
|
201
201
|
fs.writeFileSync(path.join(rulesDir, "airules.txt"), airules);
|
202
202
|
}
|
203
|
-
let packageContext = `
|
204
|
-
\n
|
205
|
-
Title: "${packageInfo.title.us}"
|
206
|
-
Description: "${packageInfo.description.us}"
|
207
|
-
Target Audience: "${targetAudience}"
|
208
|
-
Estimated Duration: "${estimatedDuration} minutes"
|
209
|
-
|
203
|
+
let packageContext = `
|
204
|
+
\n
|
205
|
+
Title: "${packageInfo.title.us}"
|
206
|
+
Description: "${packageInfo.description.us}"
|
207
|
+
Target Audience: "${targetAudience}"
|
208
|
+
Estimated Duration: "${estimatedDuration} minutes"
|
209
|
+
|
210
210
|
${contentIndex ?
|
211
|
-
`Content Index submitted by the user, use this to guide your creation. Keep in mind that your tutorial should contain these topics:
|
212
|
-
---
|
213
|
-
${contentIndex}
|
214
|
-
---
|
211
|
+
`Content Index submitted by the user, use this to guide your creation. Keep in mind that your tutorial should contain these topics:
|
212
|
+
---
|
213
|
+
${contentIndex}
|
214
|
+
---
|
215
215
|
` :
|
216
|
-
""}
|
217
|
-
|
218
|
-
This is the duration for each type of step, use it to estimate the number of steps to create:
|
216
|
+
""}
|
217
|
+
|
218
|
+
This is the duration for each type of step, use it to estimate the number of steps to create:
|
219
219
|
${Object.entries(durationByKind)
|
220
220
|
.map(([key, value]) => `${key}: ${value} minutes`)
|
221
|
-
.join("\n")}
|
222
|
-
|
223
|
-
|
224
|
-
Within the estimated duration, is possible to have the following activities:
|
225
|
-
Format=
|
226
|
-
Activity: Maximum number of steps for duration
|
227
|
-
|
228
|
-
Estimated activities:
|
229
|
-
${JSON.stringify(estimateActivities(estimatedDuration))}
|
230
|
-
|
231
|
-
You should create a tutorial that is engaging and fun to follow.
|
232
|
-
|
233
|
-
|
221
|
+
.join("\n")}
|
222
|
+
|
223
|
+
|
224
|
+
Within the estimated duration, is possible to have the following activities:
|
225
|
+
Format=
|
226
|
+
Activity: Maximum number of steps for duration
|
227
|
+
|
228
|
+
Estimated activities:
|
229
|
+
${JSON.stringify(estimateActivities(estimatedDuration))}
|
230
|
+
|
231
|
+
You should create a tutorial that is engaging and fun to follow.
|
232
|
+
|
233
|
+
|
234
234
|
${airules ?
|
235
|
-
`
|
236
|
-
This is a list of rules you need to follow when creating the tutorial:
|
237
|
-
${airules}
|
235
|
+
`
|
236
|
+
This is a list of rules you need to follow when creating the tutorial:
|
237
|
+
${airules}
|
238
238
|
` :
|
239
|
-
""}
|
239
|
+
""}
|
240
240
|
`;
|
241
241
|
const { steps, title, description, duration, difficulty } = await initializeInteractiveCreation(rigoToken, packageContext);
|
242
242
|
packageInfo.title.us = title;
|
243
243
|
packageInfo.description.us = description;
|
244
244
|
packageInfo.duration = duration;
|
245
245
|
packageInfo.difficulty = difficulty;
|
246
|
-
packageContext = `
|
247
|
-
Title: "${title}"
|
248
|
-
Description: "${description}"
|
249
|
-
Target Audience: "${targetAudience}"
|
250
|
-
List of exercises: ${steps.join(", ")}
|
251
|
-
|
252
|
-
AI Rules: ${airules}
|
246
|
+
packageContext = `
|
247
|
+
Title: "${title}"
|
248
|
+
Description: "${description}"
|
249
|
+
Target Audience: "${targetAudience}"
|
250
|
+
List of exercises: ${steps.join(", ")}
|
251
|
+
|
252
|
+
AI Rules: ${airules}
|
253
253
|
`;
|
254
254
|
const exercisesDir = path.join(tutorialDir, "exercises");
|
255
255
|
fs.ensureDirSync(exercisesDir);
|
package/lib/commands/logout.js
CHANGED
@@ -14,9 +14,9 @@ class LogoutCommand extends SessionCommand_1.default {
|
|
14
14
|
session_1.default.destroy();
|
15
15
|
}
|
16
16
|
}
|
17
|
-
LogoutCommand.description = `Describe the command here
|
18
|
-
...
|
19
|
-
Extra documentation goes here
|
17
|
+
LogoutCommand.description = `Describe the command here
|
18
|
+
...
|
19
|
+
Extra documentation goes here
|
20
20
|
`;
|
21
21
|
LogoutCommand.flags = {
|
22
22
|
// name: flags.string({char: 'n', description: 'name to print'}),
|
package/lib/commands/serve.js
CHANGED
@@ -4,7 +4,6 @@ exports.processImage = exports.createLearnJson = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
5
5
|
const command_1 = require("@oclif/command");
|
6
6
|
const buffer_1 = require("buffer");
|
7
|
-
const youtube_transcript_1 = require("youtube-transcript");
|
8
7
|
const express = require("express");
|
9
8
|
const cors = require("cors");
|
10
9
|
const path = require("path");
|
@@ -82,7 +81,6 @@ const processImage = async (url, description, rigoToken, courseSlug) => {
|
|
82
81
|
prompt: description,
|
83
82
|
callbackUrl: webhookUrl,
|
84
83
|
});
|
85
|
-
// console.log("✅ Image", imagePath, "generated successfully!")
|
86
84
|
return true;
|
87
85
|
}
|
88
86
|
catch (_a) {
|
@@ -147,6 +145,7 @@ async function startExerciseGeneration(rigoToken, steps, packageContext, exercis
|
|
147
145
|
last_lesson: lastLesson,
|
148
146
|
}, purposeSlug, webhookUrl);
|
149
147
|
console.log("README CREATOR RES", res);
|
148
|
+
return res.id;
|
150
149
|
}
|
151
150
|
async function createInitialReadme(tutorialInfo, tutorialSlug, rigoToken) {
|
152
151
|
const webhookUrl = `${process.env.HOST}/webhooks/${tutorialSlug}/initial-readme-processor`;
|
@@ -432,10 +431,18 @@ class ServeCommand extends SessionCommand_1.default {
|
|
432
431
|
previousReadme = content.toString();
|
433
432
|
}
|
434
433
|
}
|
435
|
-
await startExerciseGeneration(rigoToken, syllabusJson.lessons, syllabusJson.courseInfo, exercise, courseSlug, syllabusJson.courseInfo.purpose, previousReadme +
|
434
|
+
const completionId = await startExerciseGeneration(rigoToken, syllabusJson.lessons, syllabusJson.courseInfo, exercise, courseSlug, syllabusJson.courseInfo.purpose, previousReadme +
|
436
435
|
"\n\nThe user provided the following feedback related to the content of the course so far: \n\n" +
|
437
436
|
feedback);
|
438
437
|
syllabusJson.lessons[parseInt(position)].status = "GENERATING";
|
438
|
+
syllabusJson.lessons[parseInt(position)].translations = {
|
439
|
+
[syllabusJson.courseInfo.language || "en"]: {
|
440
|
+
completionId,
|
441
|
+
startedAt: Date.now(),
|
442
|
+
completedAt: 0,
|
443
|
+
},
|
444
|
+
};
|
445
|
+
console.log("Lesson", syllabusJson.lessons[parseInt(position)]);
|
439
446
|
if (syllabusJson.feedback &&
|
440
447
|
typeof syllabusJson.feedback === "string") {
|
441
448
|
syllabusJson.feedback += "\n\n" + feedback;
|
@@ -446,6 +453,23 @@ class ServeCommand extends SessionCommand_1.default {
|
|
446
453
|
await uploadFileToBucket(bucket, JSON.stringify(syllabusJson), `courses/${courseSlug}/.learn/initialSyllabus.json`);
|
447
454
|
res.json({ status: "SUCCESS" });
|
448
455
|
});
|
456
|
+
app.post("/actions/generate-image/:courseSlug", async (req, res) => {
|
457
|
+
const rigoToken = req.header("x-rigo-token");
|
458
|
+
const { courseSlug } = req.params;
|
459
|
+
const { image } = req.body;
|
460
|
+
if (!image) {
|
461
|
+
return res.status(400).json({
|
462
|
+
error: "Image is required",
|
463
|
+
});
|
464
|
+
}
|
465
|
+
if (!rigoToken) {
|
466
|
+
return res.status(400).json({
|
467
|
+
error: "Rigo token is required. x-rigo-token header is missing",
|
468
|
+
});
|
469
|
+
}
|
470
|
+
await (0, exports.processImage)(image.url, image.alt, rigoToken, courseSlug);
|
471
|
+
res.json({ status: "QUEUED" });
|
472
|
+
});
|
449
473
|
app.post("/webhooks/:courseSlug/exercise-processor/:lessonID/:rigoToken", async (req, res) => {
|
450
474
|
// console.log("Receiving a webhook to exercise processor")
|
451
475
|
const { courseSlug, lessonID, rigoToken } = req.params;
|
@@ -498,40 +522,55 @@ class ServeCommand extends SessionCommand_1.default {
|
|
498
522
|
log: `✅ Code file created for ${exercise.title}`,
|
499
523
|
});
|
500
524
|
}
|
501
|
-
let
|
525
|
+
let nextCompletionId = null;
|
502
526
|
if (nextExercise &&
|
503
527
|
(exerciseIndex === 0 || !(exerciseIndex % 3 === 0))) {
|
504
528
|
let feedback = "";
|
505
529
|
if (syllabusJson.feedback) {
|
506
530
|
feedback = `\n\nThe user added the following feedback with relation to the previous generations: ${syllabusJson.feedback}`;
|
507
531
|
}
|
508
|
-
startExerciseGeneration(rigoToken, syllabusJson.lessons, syllabusJson.courseInfo, nextExercise, courseSlug, syllabusJson.courseInfo.purpose, readme.parsed.content + "\n\n" + feedback);
|
509
|
-
nextStarted = true;
|
532
|
+
nextCompletionId = await startExerciseGeneration(rigoToken, syllabusJson.lessons, syllabusJson.courseInfo, nextExercise, courseSlug, syllabusJson.courseInfo.purpose, readme.parsed.content + "\n\n" + feedback);
|
510
533
|
}
|
511
534
|
else {
|
512
535
|
console.log("Stopping generation process at", exerciseIndex, exercise.title, "because it's a multiple of 3");
|
513
536
|
}
|
514
537
|
const imagesArray = (0, creatorUtilities_1.extractImagesFromMarkdown)(readability.newMarkdown);
|
515
|
-
if (imagesArray.length > 0) {
|
516
|
-
(0, creatorSocket_1.emitToCourse)(courseSlug, "course-creation", {
|
517
|
-
lesson: exSlug,
|
518
|
-
status: "pending",
|
519
|
-
log: `🔄 Generating images for ${exercise.title}`,
|
520
|
-
});
|
521
|
-
for (const image of imagesArray) {
|
522
|
-
// eslint-disable-next-line no-await-in-loop
|
523
|
-
await (0, exports.processImage)(image.url, image.alt, rigoToken, courseSlug);
|
524
|
-
}
|
525
|
-
}
|
526
538
|
const newSyllabus = Object.assign(Object.assign({}, syllabusJson), { lessons: syllabusJson.lessons.map((lesson, index) => {
|
527
539
|
if (index === exerciseIndex) {
|
528
|
-
|
540
|
+
const currentTranslations = lesson.translations || {};
|
541
|
+
let currentTranslation = currentTranslations[syllabusJson.courseInfo.language || "en"];
|
542
|
+
if (currentTranslation) {
|
543
|
+
currentTranslation.completedAt = Date.now();
|
544
|
+
}
|
545
|
+
else {
|
546
|
+
currentTranslation = {
|
547
|
+
completionId: readme.id,
|
548
|
+
startedAt: Date.now(),
|
549
|
+
completedAt: Date.now(),
|
550
|
+
};
|
551
|
+
}
|
552
|
+
currentTranslations[syllabusJson.courseInfo.language || "en"] =
|
553
|
+
currentTranslation;
|
554
|
+
return Object.assign(Object.assign({}, lesson), { generated: true, status: "DONE", translations: {
|
555
|
+
[syllabusJson.courseInfo.language || "en"]: {
|
556
|
+
completionId: nextCompletionId,
|
557
|
+
completedAt: Date.now(),
|
558
|
+
},
|
559
|
+
} });
|
529
560
|
}
|
530
|
-
if (nextExercise &&
|
531
|
-
|
561
|
+
if (nextExercise &&
|
562
|
+
nextExercise.id === lesson.id &&
|
563
|
+
nextCompletionId) {
|
564
|
+
return Object.assign(Object.assign({}, lesson), { generated: false, status: "GENERATING", translations: {
|
565
|
+
[syllabusJson.courseInfo.language || "en"]: {
|
566
|
+
completionId: nextCompletionId,
|
567
|
+
startedAt: Date.now(),
|
568
|
+
},
|
569
|
+
} });
|
532
570
|
}
|
533
571
|
return Object.assign({}, lesson);
|
534
572
|
}) });
|
573
|
+
console.log("New syllabus", newSyllabus);
|
535
574
|
await uploadFileToBucket(bucket, JSON.stringify(newSyllabus), `courses/${courseSlug}/.learn/initialSyllabus.json`);
|
536
575
|
(0, creatorSocket_1.emitToCourse)(courseSlug, "course-creation", {
|
537
576
|
lesson: exSlug,
|
@@ -936,7 +975,16 @@ class ServeCommand extends SessionCommand_1.default {
|
|
936
975
|
await uploadFileToBucket(bucket, JSON.stringify(sidebar), `${tutorialDir}/.learn/sidebar.json`);
|
937
976
|
const firstLesson = syllabus.lessons[0];
|
938
977
|
const lastResult = "---";
|
939
|
-
await startExerciseGeneration(rigoToken, syllabus.lessons, syllabus.courseInfo, firstLesson, courseSlug, syllabus.courseInfo.purpose, lastResult);
|
978
|
+
const completionId = await startExerciseGeneration(rigoToken, syllabus.lessons, syllabus.courseInfo, firstLesson, courseSlug, syllabus.courseInfo.purpose, lastResult);
|
979
|
+
if (firstLesson) {
|
980
|
+
firstLesson.translations = {
|
981
|
+
[syllabus.courseInfo.language || "en"]: {
|
982
|
+
completionId,
|
983
|
+
startedAt: Date.now(),
|
984
|
+
completedAt: 0,
|
985
|
+
},
|
986
|
+
};
|
987
|
+
}
|
940
988
|
await createInitialReadme(JSON.stringify(syllabus.courseInfo), courseSlug, rigoToken);
|
941
989
|
return res.json({
|
942
990
|
message: "Course generation started",
|
@@ -957,29 +1005,44 @@ class ServeCommand extends SessionCommand_1.default {
|
|
957
1005
|
return res.status(500).json({ error: "Error getting syllabus" });
|
958
1006
|
}
|
959
1007
|
});
|
960
|
-
app.post("/actions/continue-course/:courseSlug", async (req, res) => {
|
961
|
-
|
962
|
-
|
963
|
-
|
964
|
-
|
965
|
-
|
966
|
-
|
967
|
-
|
968
|
-
|
969
|
-
|
970
|
-
|
971
|
-
|
972
|
-
|
973
|
-
|
974
|
-
|
975
|
-
|
976
|
-
|
977
|
-
|
978
|
-
|
979
|
-
|
980
|
-
|
981
|
-
|
982
|
-
|
1008
|
+
// app.post("/actions/continue-course/:courseSlug", async (req, res) => {
|
1009
|
+
// console.log("POST /actions/continue-course/:courseSlug")
|
1010
|
+
// const { courseSlug } = req.params
|
1011
|
+
// const { feedback }: { feedback: string } = req.body
|
1012
|
+
// const rigoToken = req.header("x-rigo-token")
|
1013
|
+
// const bcToken = req.header("x-breathecode-token")
|
1014
|
+
// if (!rigoToken || !bcToken) {
|
1015
|
+
// return res.status(400).json({ error: "Missing tokens" })
|
1016
|
+
// }
|
1017
|
+
// const syllabus = await bucket.file(
|
1018
|
+
// `courses/${courseSlug}/.learn/initialSyllabus.json`
|
1019
|
+
// )
|
1020
|
+
// const [content] = await syllabus.download()
|
1021
|
+
// const syllabusJson: Syllabus = JSON.parse(content.toString())
|
1022
|
+
// const notGeneratedLessons = syllabusJson.lessons.filter(
|
1023
|
+
// lesson => !lesson.generated
|
1024
|
+
// )
|
1025
|
+
// const lastGeneratedLesson = findLast(
|
1026
|
+
// syllabusJson.lessons,
|
1027
|
+
// lesson => lesson.generated ?? false
|
1028
|
+
// )
|
1029
|
+
// console.log("ABout to generate", notGeneratedLessons.length, "lessons")
|
1030
|
+
// const firstLessonToGenerate = notGeneratedLessons[0]
|
1031
|
+
// const completionId = await startExerciseGeneration(
|
1032
|
+
// rigoToken,
|
1033
|
+
// syllabusJson.lessons,
|
1034
|
+
// syllabusJson.courseInfo,
|
1035
|
+
// firstLessonToGenerate,
|
1036
|
+
// courseSlug,
|
1037
|
+
// syllabusJson.courseInfo.purpose,
|
1038
|
+
// JSON.stringify(lastGeneratedLesson) +
|
1039
|
+
// `\n\nThe user provided this feedback in relation to the course: ${feedback}`
|
1040
|
+
// )
|
1041
|
+
// return res.json({
|
1042
|
+
// message: "Course continued",
|
1043
|
+
// slug: courseSlug,
|
1044
|
+
// })
|
1045
|
+
// })
|
983
1046
|
app.get("/courses/:courseSlug/exercises/:exerciseSlug/", async (req, res) => {
|
984
1047
|
var _a;
|
985
1048
|
console.log("GET /courses/:courseSlug/exercises/:exerciseSlug/");
|
@@ -1134,9 +1197,7 @@ class ServeCommand extends SessionCommand_1.default {
|
|
1134
1197
|
}
|
1135
1198
|
catch (error) {
|
1136
1199
|
console.error("❌ Error fetching file:", error);
|
1137
|
-
return res
|
1138
|
-
.status(500)
|
1139
|
-
.json({
|
1200
|
+
return res.status(500).json({
|
1140
1201
|
error: error.message || "Unable to fetch file",
|
1141
1202
|
});
|
1142
1203
|
}
|
@@ -1150,28 +1211,26 @@ class ServeCommand extends SessionCommand_1.default {
|
|
1150
1211
|
const ytMatch = decoded.match(YT_REGEX);
|
1151
1212
|
if (ytMatch) {
|
1152
1213
|
const videoId = ytMatch[1];
|
1153
|
-
|
1154
|
-
|
1155
|
-
const
|
1156
|
-
|
1157
|
-
|
1158
|
-
|
1159
|
-
|
1160
|
-
|
1161
|
-
|
1162
|
-
|
1163
|
-
|
1164
|
-
|
1165
|
-
catch (error) {
|
1166
|
-
|
1167
|
-
|
1168
|
-
}
|
1169
|
-
throw new Error("test");
|
1214
|
+
const resFromRigo = await axios_1.default.get(`${api_1.RIGOBOT_REALTIME_HOST}/actions/youtube-transcript/${videoId}`);
|
1215
|
+
console.log("RES FROM RIGO", resFromRigo.data);
|
1216
|
+
const transcript = resFromRigo.data.transcript;
|
1217
|
+
// let meta: any = null
|
1218
|
+
// try {
|
1219
|
+
// const { data: meta } = await axios.get(
|
1220
|
+
// "https://www.youtube.com/oembed",
|
1221
|
+
// {
|
1222
|
+
// params: { url: decoded, format: "json" },
|
1223
|
+
// }
|
1224
|
+
// )
|
1225
|
+
// console.log("META", meta)
|
1226
|
+
// } catch (error) {
|
1227
|
+
// console.error("ERROR FETCHING META", error)
|
1228
|
+
// meta = null
|
1229
|
+
// }
|
1170
1230
|
return res.json({
|
1171
1231
|
url: decoded,
|
1172
|
-
title:
|
1173
|
-
author:
|
1174
|
-
thumbnail: (meta === null || meta === void 0 ? void 0 : meta.thumbnail_url) || null,
|
1232
|
+
title: resFromRigo.data.title || null,
|
1233
|
+
author: resFromRigo.data.author || null,
|
1175
1234
|
transcript,
|
1176
1235
|
});
|
1177
1236
|
}
|
@@ -1189,9 +1248,7 @@ class ServeCommand extends SessionCommand_1.default {
|
|
1189
1248
|
}
|
1190
1249
|
catch (error) {
|
1191
1250
|
console.error("❌ /actions/fetch error:", error.message || error);
|
1192
|
-
res
|
1193
|
-
.status(500)
|
1194
|
-
.json({ error: error.message || "Failed to fetch link" });
|
1251
|
+
res.status(500).json({ error: error.message || "Failed to fetch link" });
|
1195
1252
|
}
|
1196
1253
|
});
|
1197
1254
|
app.delete("/packages/:slug", async (req, res) => {
|