@learnpack/learnpack 5.0.267 → 5.0.269
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/lib/commands/serve.js +70 -19
- package/lib/creatorDist/assets/{index-DmpsXknz.css → index-B4khtb0r.css} +3 -0
- package/lib/creatorDist/assets/{index-BXp9oelr.js → index-CQXTTbaZ.js} +2390 -2378
- package/lib/creatorDist/index.html +2 -2
- package/lib/models/creator.d.ts +1 -0
- package/package.json +1 -1
- package/src/commands/serve.ts +105 -27
- package/src/creator/src/App.tsx +12 -6
- package/src/creator/src/components/syllabus/ContentIndex.tsx +5 -0
- package/src/creator/src/locales/en.json +2 -1
- package/src/creator/src/locales/es.json +2 -1
- package/src/creator/src/utils/rigo.ts +0 -1
- package/src/creatorDist/assets/{index-DmpsXknz.css → index-B4khtb0r.css} +3 -0
- package/src/creatorDist/assets/{index-BXp9oelr.js → index-CQXTTbaZ.js} +2390 -2378
- package/src/creatorDist/index.html +2 -2
- package/src/models/creator.ts +1 -0
@@ -10,8 +10,8 @@
|
|
10
10
|
/>
|
11
11
|
|
12
12
|
<title>Learnpack Creator: Craft tutorials in seconds!</title>
|
13
|
-
<script type="module" crossorigin src="/creator/assets/index-
|
14
|
-
<link rel="stylesheet" crossorigin href="/creator/assets/index-
|
13
|
+
<script type="module" crossorigin src="/creator/assets/index-CQXTTbaZ.js"></script>
|
14
|
+
<link rel="stylesheet" crossorigin href="/creator/assets/index-B4khtb0r.css">
|
15
15
|
</head>
|
16
16
|
<body>
|
17
17
|
<div id="root"></div>
|
package/lib/models/creator.d.ts
CHANGED
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "@learnpack/learnpack",
|
3
3
|
"description": "Seamlessly build, sell and/or take interactive & auto-graded tutorials, start learning now or build a new tutorial to your audience.",
|
4
|
-
"version": "5.0.
|
4
|
+
"version": "5.0.269",
|
5
5
|
"author": "Alejandro Sanchez @alesanchezr",
|
6
6
|
"contributors": [
|
7
7
|
{
|
package/src/commands/serve.ts
CHANGED
@@ -608,6 +608,64 @@ export default class ServeCommand extends SessionCommand {
|
|
608
608
|
}
|
609
609
|
})
|
610
610
|
|
611
|
+
app.post(
|
612
|
+
"/actions/continue-generating/:courseSlug/:position",
|
613
|
+
async (req, res) => {
|
614
|
+
const { courseSlug, position } = req.params
|
615
|
+
const { feedback } = req.body
|
616
|
+
const rigoToken = req.header("x-rigo-token")
|
617
|
+
|
618
|
+
if (!rigoToken) {
|
619
|
+
return res.status(400).json({
|
620
|
+
error: "Rigo token is required. x-rigo-token header is missing",
|
621
|
+
})
|
622
|
+
}
|
623
|
+
|
624
|
+
const syllabus = await bucket.file(
|
625
|
+
`courses/${courseSlug}/.learn/initialSyllabus.json`
|
626
|
+
)
|
627
|
+
const [content] = await syllabus.download()
|
628
|
+
const syllabusJson: Syllabus = JSON.parse(content.toString())
|
629
|
+
|
630
|
+
const exercise = syllabusJson.lessons[parseInt(position)]
|
631
|
+
|
632
|
+
// previous exercise
|
633
|
+
let previousReadme = "---"
|
634
|
+
const previousExercise = syllabusJson.lessons[parseInt(position) - 1]
|
635
|
+
if (previousExercise) {
|
636
|
+
// Get the readme of the previous exercise
|
637
|
+
const exSlug = slugify(
|
638
|
+
previousExercise.id + "-" + previousExercise.title
|
639
|
+
)
|
640
|
+
// llist the files un
|
641
|
+
const [files] = await bucket.getFiles({
|
642
|
+
prefix: `courses/${courseSlug}/exercises/${exSlug}/README`,
|
643
|
+
})
|
644
|
+
// select any README
|
645
|
+
const readmeFiles = files.map(f => f.name)
|
646
|
+
const readmeFile = readmeFiles.find(f => f.includes("README"))
|
647
|
+
if (readmeFile) {
|
648
|
+
const [content] = await bucket.file(readmeFile).download()
|
649
|
+
previousReadme = content.toString()
|
650
|
+
}
|
651
|
+
}
|
652
|
+
|
653
|
+
await startExerciseGeneration(
|
654
|
+
bucket,
|
655
|
+
rigoToken,
|
656
|
+
syllabusJson.lessons,
|
657
|
+
syllabusJson.courseInfo,
|
658
|
+
exercise,
|
659
|
+
`courses/${courseSlug}`,
|
660
|
+
courseSlug,
|
661
|
+
syllabusJson.courseInfo.purpose,
|
662
|
+
previousReadme +
|
663
|
+
"\n\nThe user provided the following feedback related to the content of the course so far: \n\n" +
|
664
|
+
feedback
|
665
|
+
)
|
666
|
+
}
|
667
|
+
)
|
668
|
+
|
611
669
|
app.post(
|
612
670
|
"/webhooks/:courseSlug/exercise-processor/:lessonID/:rigoToken",
|
613
671
|
async (req, res) => {
|
@@ -620,6 +678,15 @@ export default class ServeCommand extends SessionCommand {
|
|
620
678
|
)
|
621
679
|
const [content] = await syllabus.download()
|
622
680
|
const syllabusJson: Syllabus = JSON.parse(content.toString())
|
681
|
+
|
682
|
+
if (readme.status === "ERROR") {
|
683
|
+
emitToCourse(courseSlug, "course-creation", {
|
684
|
+
lesson: lessonID,
|
685
|
+
status: "error",
|
686
|
+
log: `❌ Error generating the lesson ${lessonID}`,
|
687
|
+
})
|
688
|
+
}
|
689
|
+
|
623
690
|
const exerciseIndex = syllabusJson.lessons.findIndex(
|
624
691
|
lesson => lesson.id === lessonID
|
625
692
|
)
|
@@ -632,17 +699,15 @@ export default class ServeCommand extends SessionCommand {
|
|
632
699
|
}
|
633
700
|
|
634
701
|
const exercise = syllabusJson.lessons[exerciseIndex]
|
635
|
-
|
636
|
-
const nextExercise = syllabusJson.lessons[exerciseIndex + 1] || null
|
637
|
-
|
638
702
|
if (!exercise) {
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
)
|
643
|
-
return res.json({ status: "SUCCESS" })
|
703
|
+
return res.json({
|
704
|
+
status: "ERROR",
|
705
|
+
error: "Exercise not found or is invalid",
|
706
|
+
})
|
644
707
|
}
|
645
708
|
|
709
|
+
const nextExercise = syllabusJson.lessons[exerciseIndex + 1] || null
|
710
|
+
|
646
711
|
const exSlug = slugify(exercise.id + "-" + exercise.title)
|
647
712
|
|
648
713
|
const readability = checkReadability(
|
@@ -660,11 +725,9 @@ export default class ServeCommand extends SessionCommand {
|
|
660
725
|
const exercisesDir = `courses/${courseSlug}/exercises`
|
661
726
|
const targetDir = `${exercisesDir}/${exSlug}`
|
662
727
|
|
663
|
-
const readmeFilename = `README
|
664
|
-
readme.parsed.language_code
|
665
|
-
|
666
|
-
""
|
667
|
-
}md`
|
728
|
+
const readmeFilename = `README${getReadmeExtension(
|
729
|
+
readme.parsed.language_code
|
730
|
+
)}`
|
668
731
|
|
669
732
|
await uploadFileToBucket(
|
670
733
|
bucket,
|
@@ -689,12 +752,16 @@ export default class ServeCommand extends SessionCommand {
|
|
689
752
|
)
|
690
753
|
emitToCourse(courseSlug, "course-creation", {
|
691
754
|
lesson: exSlug,
|
692
|
-
status: "
|
755
|
+
status: "generating",
|
693
756
|
log: `✅ Code file created for ${exercise.title}`,
|
694
757
|
})
|
695
758
|
}
|
696
759
|
|
697
|
-
|
760
|
+
let nextStarted = false
|
761
|
+
if (
|
762
|
+
nextExercise &&
|
763
|
+
(exerciseIndex === 0 || !(exerciseIndex % 3 === 0))
|
764
|
+
) {
|
698
765
|
startExerciseGeneration(
|
699
766
|
bucket,
|
700
767
|
rigoToken,
|
@@ -706,6 +773,14 @@ export default class ServeCommand extends SessionCommand {
|
|
706
773
|
syllabusJson.courseInfo.purpose,
|
707
774
|
readme.parsed.content
|
708
775
|
)
|
776
|
+
nextStarted = true
|
777
|
+
} else {
|
778
|
+
console.log(
|
779
|
+
"Stopping generation process at",
|
780
|
+
exerciseIndex,
|
781
|
+
exercise.title,
|
782
|
+
"because it's a multiple of 3"
|
783
|
+
)
|
709
784
|
}
|
710
785
|
|
711
786
|
const imagesArray: any[] = extractImagesFromMarkdown(
|
@@ -724,29 +799,31 @@ export default class ServeCommand extends SessionCommand {
|
|
724
799
|
}
|
725
800
|
}
|
726
801
|
|
727
|
-
emitToCourse(courseSlug, "course-creation", {
|
728
|
-
lesson: exSlug,
|
729
|
-
status: "done",
|
730
|
-
log: `✅ The lesson ${exercise.id} - ${exercise.title} has been generated successfully!`,
|
731
|
-
})
|
732
|
-
|
733
802
|
const newSyllabus = {
|
734
803
|
...syllabusJson,
|
735
804
|
lessons: syllabusJson.lessons.map(lesson => {
|
736
805
|
if (lesson.id === exercise.id) {
|
737
|
-
return { ...lesson, generated: true }
|
806
|
+
return { ...lesson, generated: true, status: "DONE" }
|
738
807
|
}
|
739
808
|
|
740
|
-
|
809
|
+
if (nextExercise && nextExercise.id === lesson.id && !nextStarted) {
|
810
|
+
return { ...lesson, generated: false, status: "GENERATING" }
|
811
|
+
}
|
812
|
+
|
813
|
+
return { ...lesson }
|
741
814
|
}),
|
742
815
|
}
|
743
|
-
|
744
816
|
await uploadFileToBucket(
|
745
817
|
bucket,
|
746
818
|
JSON.stringify(newSyllabus),
|
747
819
|
`courses/${courseSlug}/.learn/initialSyllabus.json`
|
748
820
|
)
|
749
821
|
|
822
|
+
emitToCourse(courseSlug, "course-creation", {
|
823
|
+
lesson: exSlug,
|
824
|
+
status: "done",
|
825
|
+
log: `✅ The lesson ${exercise.id} - ${exercise.title} has been generated successfully!`,
|
826
|
+
})
|
750
827
|
res.json({ status: "SUCCESS" })
|
751
828
|
}
|
752
829
|
)
|
@@ -1321,12 +1398,13 @@ export default class ServeCommand extends SessionCommand {
|
|
1321
1398
|
...syllabus,
|
1322
1399
|
lessons: syllabus.lessons.map((lesson, index) => {
|
1323
1400
|
if (index < 1) {
|
1324
|
-
return { ...lesson, generated:
|
1401
|
+
return { ...lesson, generated: false, status: "GENERATING" }
|
1325
1402
|
}
|
1326
1403
|
|
1327
1404
|
return {
|
1328
1405
|
...lesson,
|
1329
1406
|
generated: false,
|
1407
|
+
status: "PENDING",
|
1330
1408
|
}
|
1331
1409
|
}),
|
1332
1410
|
}
|
@@ -1343,7 +1421,7 @@ export default class ServeCommand extends SessionCommand {
|
|
1343
1421
|
)
|
1344
1422
|
const firstLesson = syllabus.lessons[0]
|
1345
1423
|
|
1346
|
-
const lastResult = "
|
1424
|
+
const lastResult = "---"
|
1347
1425
|
|
1348
1426
|
await startExerciseGeneration(
|
1349
1427
|
bucket,
|
@@ -1364,7 +1442,7 @@ export default class ServeCommand extends SessionCommand {
|
|
1364
1442
|
)
|
1365
1443
|
|
1366
1444
|
return res.json({
|
1367
|
-
message: "Course
|
1445
|
+
message: "Course generation started",
|
1368
1446
|
slug: syllabus.courseInfo.slug,
|
1369
1447
|
})
|
1370
1448
|
})
|
package/src/creator/src/App.tsx
CHANGED
@@ -30,6 +30,7 @@ import { useTranslation } from "react-i18next"
|
|
30
30
|
import NotificationListener from "./components/NotificationListener"
|
31
31
|
import { slugify } from "./utils/creatorUtils"
|
32
32
|
import TurnstileModal from "./components/TurnstileModal"
|
33
|
+
import { TMessage } from "./components/Message"
|
33
34
|
|
34
35
|
function App() {
|
35
36
|
const navigate = useNavigate()
|
@@ -503,7 +504,7 @@ function App() {
|
|
503
504
|
i18n.changeLanguage(res.parsed.languageCode)
|
504
505
|
}
|
505
506
|
|
506
|
-
|
507
|
+
let initialMessages: TMessage[] = [
|
507
508
|
{
|
508
509
|
type: "user",
|
509
510
|
content: formState.description,
|
@@ -512,15 +513,20 @@ function App() {
|
|
512
513
|
type: "assistant",
|
513
514
|
content: res.parsed.aiMessage,
|
514
515
|
},
|
515
|
-
|
516
|
+
]
|
517
|
+
|
518
|
+
if (lessons.length > 0) {
|
519
|
+
initialMessages.push({
|
516
520
|
type: "assistant",
|
517
521
|
content: t("contentIndex.okMessage"),
|
518
|
-
}
|
519
|
-
{
|
522
|
+
})
|
523
|
+
initialMessages.push({
|
520
524
|
type: "assistant",
|
521
525
|
content: t("contentIndex.instructionsMessage"),
|
522
|
-
}
|
523
|
-
|
526
|
+
})
|
527
|
+
}
|
528
|
+
|
529
|
+
setMessages(initialMessages)
|
524
530
|
navigate("/creator/syllabus")
|
525
531
|
setFormState({
|
526
532
|
isCompleted: false,
|
@@ -246,6 +246,11 @@ export const ContentIndex = ({
|
|
246
246
|
) : (
|
247
247
|
<>
|
248
248
|
<ContentSecondaryHeader messages={messages} />
|
249
|
+
{syllabus.lessons.length === 0 && messages.length < 3 && (
|
250
|
+
<div className="text-center text-gray-200 font-bold text-lg">
|
251
|
+
{t("contentIndex.noLessons")}
|
252
|
+
</div>
|
253
|
+
)}
|
249
254
|
{syllabus.lessons.map((lesson, index) => (
|
250
255
|
<div key={lesson.uid + index}>
|
251
256
|
<LessonItem
|
@@ -81,7 +81,8 @@
|
|
81
81
|
"contentIndex": {
|
82
82
|
"subText": {
|
83
83
|
"first": "It includes a mix of reading, coding exercises, and quizzes. Give it a look and let me know if it aligns with your expectations or if there are any changes you'd like to make.",
|
84
|
-
"second": "Based on your input, here is the new syllabus, updates are highlighted in yellow"
|
84
|
+
"second": "Based on your input, here is the new syllabus, updates are highlighted in yellow",
|
85
|
+
"noLessons": "The content could not be generated, please talk with Rigobot to give it more context."
|
85
86
|
},
|
86
87
|
"revertChanges": "Revert changes",
|
87
88
|
"changesReverted": "Changes reverted!",
|
@@ -81,7 +81,8 @@
|
|
81
81
|
"contentIndex": {
|
82
82
|
"subText": {
|
83
83
|
"first": "Incluye una mezcla de lectura, ejercicios de codificación y cuestionarios. Dále un vistazo y dímelo si coincide con tus expectativas o si hay algún cambio que te gustaría hacer.",
|
84
|
-
"second": "Basado en tu entrada, aquí está el nuevo plan de estudios, los cambios se resaltan en amarillo"
|
84
|
+
"second": "Basado en tu entrada, aquí está el nuevo plan de estudios, los cambios se resaltan en amarillo",
|
85
|
+
"noLessons": "El contenido no pudo ser generado, por favor habla con Rigobot para darle más contexto."
|
85
86
|
},
|
86
87
|
"revertChanges": "Revertir cambios",
|
87
88
|
"changesReverted": "Cambios revertidos!",
|