@learnpack/learnpack 5.0.313 → 5.0.315
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 +341 -274
- package/lib/utils/creatorUtilities.d.ts +2 -0
- package/lib/utils/creatorUtilities.js +37 -14
- package/lib/utils/rigoActions.d.ts +7 -0
- package/lib/utils/rigoActions.js +17 -1
- package/package.json +1 -1
- package/src/commands/serve.ts +422 -413
- package/src/utils/creatorUtilities.ts +536 -504
- package/src/utils/rigoActions.ts +29 -0
package/lib/commands/serve.js
CHANGED
|
@@ -165,29 +165,13 @@ const createMultiLangAsset = async (bucket, rigoToken, bcToken, courseSlug, cour
|
|
|
165
165
|
all_translations.push(asset.slug);
|
|
166
166
|
}
|
|
167
167
|
};
|
|
168
|
-
async function startExerciseGeneration(rigoToken, steps, packageContext, exercise, courseSlug, purposeSlug, lastLesson = "") {
|
|
169
|
-
const exSlug = (0, creatorUtilities_2.slugify)(exercise.id + "-" + exercise.title);
|
|
170
|
-
console.log("Starting generation of", exSlug);
|
|
171
|
-
const webhookUrl = `${process.env.HOST}/webhooks/${courseSlug}/exercise-processor/${exercise.id}/${rigoToken}`;
|
|
172
|
-
const res = await (0, rigoActions_1.readmeCreator)(rigoToken.trim(), {
|
|
173
|
-
title: `${exercise.id} - ${exercise.title}`,
|
|
174
|
-
output_lang: packageContext.language || "en",
|
|
175
|
-
list_of_exercises: JSON.stringify(steps.map(step => step.id + "-" + step.title)),
|
|
176
|
-
tutorial_description: JSON.stringify(cleanFormState(packageContext)),
|
|
177
|
-
lesson_description: exercise.description,
|
|
178
|
-
kind: exercise.type.toLowerCase(),
|
|
179
|
-
last_lesson: lastLesson,
|
|
180
|
-
}, purposeSlug, webhookUrl);
|
|
181
|
-
console.log("README CREATOR RES", res);
|
|
182
|
-
return res.id;
|
|
183
|
-
}
|
|
184
168
|
const lessonCleaner = (lesson) => {
|
|
185
169
|
return Object.assign(Object.assign({}, lesson), { duration: undefined, generated: undefined, status: undefined, translations: undefined, uid: undefined, initialContent: undefined, locked: undefined });
|
|
186
170
|
};
|
|
187
171
|
async function startInitialContentGeneration(rigoToken, steps, packageContext, exercise, courseSlug, purposeSlug, lastLesson = "") {
|
|
188
172
|
const exSlug = (0, creatorUtilities_2.slugify)(exercise.id + "-" + exercise.title);
|
|
189
173
|
console.log("Starting initial content generation for", exSlug);
|
|
190
|
-
const webhookUrl = `${process.env.HOST}/webhooks/${courseSlug}/initial-content-processor/${exercise.
|
|
174
|
+
const webhookUrl = `${process.env.HOST}/webhooks/${courseSlug}/initial-content-processor/${exercise.uid}/${rigoToken}`;
|
|
191
175
|
// Emit notification that initial content generation is starting
|
|
192
176
|
(0, creatorSocket_1.emitToCourse)(courseSlug, "course-creation", {
|
|
193
177
|
lesson: exSlug,
|
|
@@ -213,7 +197,7 @@ async function startInitialContentGeneration(rigoToken, steps, packageContext, e
|
|
|
213
197
|
async function startInteractivityGeneration(rigoToken, steps, packageContext, exercise, courseSlug, purposeSlug, bucket, lastLesson = "") {
|
|
214
198
|
const exSlug = (0, creatorUtilities_2.slugify)(exercise.id + "-" + exercise.title);
|
|
215
199
|
console.log("Starting interactivity generation for", exSlug);
|
|
216
|
-
const webhookUrl = `${process.env.HOST}/webhooks/${courseSlug}/interactivity-processor/${exercise.
|
|
200
|
+
const webhookUrl = `${process.env.HOST}/webhooks/${courseSlug}/interactivity-processor/${exercise.uid}/${rigoToken}`;
|
|
217
201
|
// Emit notification that interactivity generation is starting
|
|
218
202
|
(0, creatorSocket_1.emitToCourse)(courseSlug, "course-creation", {
|
|
219
203
|
lesson: exSlug,
|
|
@@ -221,7 +205,6 @@ async function startInteractivityGeneration(rigoToken, steps, packageContext, ex
|
|
|
221
205
|
log: `🔄 Starting interactivity generation for lesson: ${exercise.title}`,
|
|
222
206
|
});
|
|
223
207
|
const componentsYml = await fetchComponentsYml();
|
|
224
|
-
// Get current syllabus to include used_components
|
|
225
208
|
const currentSyllabus = await getSyllabus(courseSlug, bucket);
|
|
226
209
|
const fullSyllabus = {
|
|
227
210
|
steps: steps.map(lessonCleaner),
|
|
@@ -238,7 +221,6 @@ async function startInteractivityGeneration(rigoToken, steps, packageContext, ex
|
|
|
238
221
|
output_language: packageContext.language || "en",
|
|
239
222
|
current_syllabus: JSON.stringify(fullSyllabus),
|
|
240
223
|
}, webhookUrl);
|
|
241
|
-
console.log("INTERACTIVITY GENERATOR RES", res);
|
|
242
224
|
return res.id;
|
|
243
225
|
}
|
|
244
226
|
async function createInitialReadme(tutorialInfo, tutorialSlug, rigoToken) {
|
|
@@ -254,6 +236,11 @@ async function createInitialReadme(tutorialInfo, tutorialSlug, rigoToken) {
|
|
|
254
236
|
console.error("Error creating initial readme", error);
|
|
255
237
|
}
|
|
256
238
|
}
|
|
239
|
+
const getConfigJSON = async (bucket, courseSlug) => {
|
|
240
|
+
const configFile = await bucket.file(`courses/${courseSlug}/.learn/config.json`);
|
|
241
|
+
const [content] = await configFile.download();
|
|
242
|
+
return JSON.parse(content.toString());
|
|
243
|
+
};
|
|
257
244
|
async function getSyllabus(courseSlug, bucket) {
|
|
258
245
|
const syllabus = await bucket.file(`courses/${courseSlug}/.learn/initialSyllabus.json`);
|
|
259
246
|
const [content] = await syllabus.download();
|
|
@@ -280,24 +267,25 @@ async function updateUsedComponents(courseSlug, usedComponents, bucket) {
|
|
|
280
267
|
console.log("Updated component usage:", syllabus.used_components);
|
|
281
268
|
await saveSyllabus(courseSlug, syllabus, bucket);
|
|
282
269
|
}
|
|
283
|
-
async function updateLessonWithInitialContent(courseSlug,
|
|
270
|
+
async function updateLessonWithInitialContent(courseSlug, lessonUID, initialResponse, bucket) {
|
|
284
271
|
const syllabus = await getSyllabus(courseSlug, bucket);
|
|
285
|
-
const lessonIndex = syllabus.lessons.findIndex(lesson => lesson.
|
|
272
|
+
const lessonIndex = syllabus.lessons.findIndex(lesson => lesson.uid === lessonUID);
|
|
286
273
|
if (lessonIndex === -1) {
|
|
287
|
-
console.error(`Lesson ${
|
|
288
|
-
return;
|
|
274
|
+
console.error(`Lesson ${lessonUID} not found in syllabus`);
|
|
275
|
+
return null;
|
|
289
276
|
}
|
|
290
277
|
const lesson = syllabus.lessons[lessonIndex];
|
|
291
278
|
// Update initial content
|
|
292
279
|
lesson.initialContent = initialResponse.lesson_content;
|
|
293
280
|
await saveSyllabus(courseSlug, syllabus, bucket);
|
|
281
|
+
return lesson;
|
|
294
282
|
}
|
|
295
|
-
async function updateLessonStatusToError(courseSlug,
|
|
283
|
+
async function updateLessonStatusToError(courseSlug, lessonUID, bucket) {
|
|
296
284
|
try {
|
|
297
285
|
const syllabus = await getSyllabus(courseSlug, bucket);
|
|
298
|
-
const lessonIndex = syllabus.lessons.findIndex(lesson => lesson.
|
|
286
|
+
const lessonIndex = syllabus.lessons.findIndex(lesson => lesson.uid === lessonUID);
|
|
299
287
|
if (lessonIndex === -1) {
|
|
300
|
-
console.error(`Lesson ${
|
|
288
|
+
console.error(`Lesson ${lessonUID} not found in syllabus when updating status to error`);
|
|
301
289
|
return;
|
|
302
290
|
}
|
|
303
291
|
const lesson = syllabus.lessons[lessonIndex];
|
|
@@ -318,10 +306,10 @@ async function updateLessonStatusToError(courseSlug, lessonID, bucket) {
|
|
|
318
306
|
}
|
|
319
307
|
lesson.translations = currentTranslations;
|
|
320
308
|
await saveSyllabus(courseSlug, syllabus, bucket);
|
|
321
|
-
console.log(`Updated lesson ${
|
|
309
|
+
console.log(`Updated lesson ${lessonUID} status to ERROR in syllabus`);
|
|
322
310
|
}
|
|
323
311
|
catch (error) {
|
|
324
|
-
console.error(`Error updating lesson ${
|
|
312
|
+
console.error(`Error updating lesson ${lessonUID} status to ERROR:`, error);
|
|
325
313
|
}
|
|
326
314
|
}
|
|
327
315
|
async function continueWithNextLesson(courseSlug, currentExerciseIndex, rigoToken, finalContent, bucket) {
|
|
@@ -689,18 +677,23 @@ class ServeCommand extends SessionCommand_1.default {
|
|
|
689
677
|
res.status(500).json({ error: error.message });
|
|
690
678
|
}
|
|
691
679
|
});
|
|
692
|
-
app.post("/actions/continue-generating/:courseSlug/:
|
|
693
|
-
const { courseSlug,
|
|
680
|
+
app.post("/actions/continue-generating/:courseSlug/:lessonUid", async (req, res) => {
|
|
681
|
+
const { courseSlug, lessonUid } = req.params;
|
|
694
682
|
const { feedback, mode } = req.body;
|
|
695
683
|
const rigoToken = req.header("x-rigo-token");
|
|
684
|
+
console.log("CONTINUE GENERATING REQUEST RECEIVED");
|
|
685
|
+
// console.log("COURSE SLUG", courseSlug);
|
|
686
|
+
console.log("LESSON UID", lessonUid);
|
|
687
|
+
// console.log("FEEDBACK", feedback);
|
|
688
|
+
// console.log("MODE", mode);
|
|
696
689
|
if (!rigoToken) {
|
|
697
690
|
return res.status(400).json({
|
|
698
691
|
error: "Rigo token is required. x-rigo-token header is missing",
|
|
699
692
|
});
|
|
700
693
|
}
|
|
701
694
|
const syllabus = await getSyllabus(courseSlug, bucket);
|
|
702
|
-
const exercise = syllabus.lessons.find(lesson => lesson.
|
|
703
|
-
const exerciseIndex = syllabus.lessons.findIndex(lesson => lesson.
|
|
695
|
+
const exercise = syllabus.lessons.find(lesson => lesson.uid === lessonUid);
|
|
696
|
+
const exerciseIndex = syllabus.lessons.findIndex(lesson => lesson.uid === lessonUid);
|
|
704
697
|
// previous exercise
|
|
705
698
|
let previousReadme = "---";
|
|
706
699
|
const previousExercise = syllabus.lessons[exerciseIndex - 1];
|
|
@@ -819,189 +812,255 @@ class ServeCommand extends SessionCommand_1.default {
|
|
|
819
812
|
});
|
|
820
813
|
}
|
|
821
814
|
});
|
|
822
|
-
app.post(
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
815
|
+
// app.post(
|
|
816
|
+
// "/webhooks/:courseSlug/exercise-processor/:lessonID/:rigoToken",
|
|
817
|
+
// async (req, res) => {
|
|
818
|
+
// // console.log("Receiving a webhook to exercise processor")
|
|
819
|
+
// const { courseSlug, lessonID, rigoToken } = req.params
|
|
820
|
+
// const readme = req.body
|
|
821
|
+
// const syllabus = await bucket.file(
|
|
822
|
+
// `courses/${courseSlug}/.learn/initialSyllabus.json`
|
|
823
|
+
// )
|
|
824
|
+
// const [content] = await syllabus.download()
|
|
825
|
+
// const syllabusJson: Syllabus = JSON.parse(content.toString())
|
|
826
|
+
// if (readme.status === "ERROR") {
|
|
827
|
+
// emitToCourse(courseSlug, "course-creation", {
|
|
828
|
+
// lesson: lessonID,
|
|
829
|
+
// status: "error",
|
|
830
|
+
// log: `❌ Error generating the lesson ${lessonID}`,
|
|
831
|
+
// })
|
|
832
|
+
// }
|
|
833
|
+
// const exerciseIndex = syllabusJson.lessons.findIndex(
|
|
834
|
+
// lesson => lesson.id === lessonID
|
|
835
|
+
// )
|
|
836
|
+
// if (exerciseIndex === -1) {
|
|
837
|
+
// console.log(
|
|
838
|
+
// "Exercise not found receiving webhook, this should not happen",
|
|
839
|
+
// lessonID
|
|
840
|
+
// )
|
|
841
|
+
// return res.json({ status: "ERROR", error: "Exercise not found" })
|
|
842
|
+
// }
|
|
843
|
+
// const exercise = syllabusJson.lessons[exerciseIndex]
|
|
844
|
+
// if (!exercise) {
|
|
845
|
+
// return res.json({
|
|
846
|
+
// status: "ERROR",
|
|
847
|
+
// error: "Exercise not found or is invalid",
|
|
848
|
+
// })
|
|
849
|
+
// }
|
|
850
|
+
// const nextExercise = syllabusJson.lessons[exerciseIndex + 1] || null
|
|
851
|
+
// const exSlug = slugify(exercise.id + "-" + exercise.title)
|
|
852
|
+
// const readability = checkReadability(
|
|
853
|
+
// readme.parsed.content,
|
|
854
|
+
// PARAMS.max_words,
|
|
855
|
+
// 3
|
|
856
|
+
// )
|
|
857
|
+
// emitToCourse(courseSlug, "course-creation", {
|
|
858
|
+
// lesson: exSlug,
|
|
859
|
+
// status: "generating",
|
|
860
|
+
// log: `🔄 The lesson ${exercise.title} has a readability score of ${readability.fkglResult.fkgl}`,
|
|
861
|
+
// })
|
|
862
|
+
// const exercisesDir = `courses/${courseSlug}/exercises`
|
|
863
|
+
// const targetDir = `${exercisesDir}/${exSlug}`
|
|
864
|
+
// const readmeFilename = `README${getReadmeExtension(
|
|
865
|
+
// readme.parsed.language_code
|
|
866
|
+
// )}`
|
|
867
|
+
// await uploadFileToBucket(
|
|
868
|
+
// bucket,
|
|
869
|
+
// readability.newMarkdown,
|
|
870
|
+
// `${targetDir}/${readmeFilename}`
|
|
871
|
+
// )
|
|
872
|
+
// if (
|
|
873
|
+
// exercise.type.toLowerCase() === "code" &&
|
|
874
|
+
// readme.parsed.codefile_content
|
|
875
|
+
// ) {
|
|
876
|
+
// emitToCourse(courseSlug, "course-creation", {
|
|
877
|
+
// lesson: exSlug,
|
|
878
|
+
// status: "generating",
|
|
879
|
+
// log: `🔄 Creating code file for ${exercise.title}`,
|
|
880
|
+
// })
|
|
881
|
+
// await uploadFileToBucket(
|
|
882
|
+
// bucket,
|
|
883
|
+
// readme.parsed.codefile_content,
|
|
884
|
+
// `${targetDir}/${readme.parsed.codefile_name.toLowerCase().trim()}`
|
|
885
|
+
// )
|
|
886
|
+
// emitToCourse(courseSlug, "course-creation", {
|
|
887
|
+
// lesson: exSlug,
|
|
888
|
+
// status: "generating",
|
|
889
|
+
// log: `✅ Code file created for ${exercise.title}`,
|
|
890
|
+
// })
|
|
891
|
+
// if (readme.parsed.solution_content) {
|
|
892
|
+
// const codeFileName = readme.parsed.codefile_name
|
|
893
|
+
// .toLowerCase()
|
|
894
|
+
// .trim()
|
|
895
|
+
// const solutionFileName = "solution.hide." + codeFileName
|
|
896
|
+
// await uploadFileToBucket(
|
|
897
|
+
// bucket,
|
|
898
|
+
// readme.parsed.solution_content,
|
|
899
|
+
// `${targetDir}/${solutionFileName}`
|
|
900
|
+
// )
|
|
901
|
+
// emitToCourse(courseSlug, "course-creation", {
|
|
902
|
+
// lesson: exSlug,
|
|
903
|
+
// status: "generating",
|
|
904
|
+
// log: `✅ Solution file created for ${exercise.title}`,
|
|
905
|
+
// })
|
|
906
|
+
// }
|
|
907
|
+
// }
|
|
908
|
+
// let nextCompletionId: number | null = null
|
|
909
|
+
// if (
|
|
910
|
+
// nextExercise &&
|
|
911
|
+
// (exerciseIndex === 0 ||
|
|
912
|
+
// !(exerciseIndex % 3 === 0) ||
|
|
913
|
+
// syllabusJson.generationMode === "continue-with-all")
|
|
914
|
+
// ) {
|
|
915
|
+
// let feedback = ""
|
|
916
|
+
// if (syllabusJson.feedback) {
|
|
917
|
+
// feedback = `\n\nThe user added the following feedback with relation to the previous generations: ${syllabusJson.feedback}`
|
|
918
|
+
// }
|
|
919
|
+
// nextCompletionId = await startExerciseGeneration(
|
|
920
|
+
// rigoToken,
|
|
921
|
+
// syllabusJson.lessons,
|
|
922
|
+
// syllabusJson.courseInfo,
|
|
923
|
+
// nextExercise,
|
|
924
|
+
// courseSlug,
|
|
925
|
+
// syllabusJson.courseInfo.purpose,
|
|
926
|
+
// readme.parsed.content + "\n\n" + feedback
|
|
927
|
+
// )
|
|
928
|
+
// } else {
|
|
929
|
+
// console.log(
|
|
930
|
+
// "Stopping generation process at",
|
|
931
|
+
// exerciseIndex,
|
|
932
|
+
// exercise.title,
|
|
933
|
+
// "because it's a multiple of 3"
|
|
934
|
+
// )
|
|
935
|
+
// }
|
|
936
|
+
// const newSyllabus = {
|
|
937
|
+
// ...syllabusJson,
|
|
938
|
+
// lessons: syllabusJson.lessons.map((lesson, index) => {
|
|
939
|
+
// if (index === exerciseIndex) {
|
|
940
|
+
// const currentTranslations = lesson.translations || {}
|
|
941
|
+
// let currentTranslation =
|
|
942
|
+
// currentTranslations[syllabusJson.courseInfo.language || "en"]
|
|
943
|
+
// if (currentTranslation) {
|
|
944
|
+
// currentTranslation.completedAt = Date.now()
|
|
945
|
+
// } else {
|
|
946
|
+
// currentTranslation = {
|
|
947
|
+
// completionId: readme.id,
|
|
948
|
+
// startedAt: Date.now(),
|
|
949
|
+
// completedAt: Date.now(),
|
|
950
|
+
// }
|
|
951
|
+
// }
|
|
952
|
+
// currentTranslations[syllabusJson.courseInfo.language || "en"] =
|
|
953
|
+
// currentTranslation
|
|
954
|
+
// return {
|
|
955
|
+
// ...lesson,
|
|
956
|
+
// generated: true,
|
|
957
|
+
// status: "DONE",
|
|
958
|
+
// translations: {
|
|
959
|
+
// [syllabusJson.courseInfo.language || "en"]: {
|
|
960
|
+
// completionId: nextCompletionId,
|
|
961
|
+
// completedAt: Date.now(),
|
|
962
|
+
// },
|
|
963
|
+
// },
|
|
964
|
+
// }
|
|
965
|
+
// }
|
|
966
|
+
// if (
|
|
967
|
+
// nextExercise &&
|
|
968
|
+
// nextExercise.id === lesson.id &&
|
|
969
|
+
// nextCompletionId
|
|
970
|
+
// ) {
|
|
971
|
+
// return {
|
|
972
|
+
// ...lesson,
|
|
973
|
+
// generated: false,
|
|
974
|
+
// status: "GENERATING",
|
|
975
|
+
// translations: {
|
|
976
|
+
// [syllabusJson.courseInfo.language || "en"]: {
|
|
977
|
+
// completionId: nextCompletionId,
|
|
978
|
+
// startedAt: Date.now(),
|
|
979
|
+
// },
|
|
980
|
+
// },
|
|
981
|
+
// }
|
|
982
|
+
// }
|
|
983
|
+
// return { ...lesson }
|
|
984
|
+
// }),
|
|
985
|
+
// }
|
|
986
|
+
// console.log("New syllabus", newSyllabus)
|
|
987
|
+
// await uploadFileToBucket(
|
|
988
|
+
// bucket,
|
|
989
|
+
// JSON.stringify(newSyllabus),
|
|
990
|
+
// `courses/${courseSlug}/.learn/initialSyllabus.json`
|
|
991
|
+
// )
|
|
992
|
+
// emitToCourse(courseSlug, "course-creation", {
|
|
993
|
+
// lesson: exSlug,
|
|
994
|
+
// status: "done",
|
|
995
|
+
// log: `✅ The lesson ${exercise.id} - ${exercise.title} has been generated successfully!`,
|
|
996
|
+
// })
|
|
997
|
+
// res.json({ status: "SUCCESS" })
|
|
998
|
+
// }
|
|
999
|
+
// )
|
|
1000
|
+
// Phase 1: Initial content generation webhook
|
|
1001
|
+
app.post("/webhooks/:courseSlug/initial-content-processor/:lessonUID/:rigoToken", async (req, res) => {
|
|
1002
|
+
const { courseSlug, lessonUID, rigoToken } = req.params;
|
|
1003
|
+
const response = req.body;
|
|
1004
|
+
console.log("RECEIVING INITIAL CONTENT WEBHOOK", response);
|
|
1005
|
+
const syllabus = await getSyllabus(courseSlug, bucket);
|
|
1006
|
+
const exerciseIndex = syllabus.lessons.findIndex(lesson => lesson.uid === lessonUID);
|
|
837
1007
|
if (exerciseIndex === -1) {
|
|
838
|
-
console.
|
|
1008
|
+
console.error("Exercise not found receiving webhook:", lessonUID);
|
|
839
1009
|
return res.json({ status: "ERROR", error: "Exercise not found" });
|
|
840
1010
|
}
|
|
841
|
-
|
|
842
|
-
if (!exercise) {
|
|
843
|
-
return res.json({
|
|
844
|
-
status: "ERROR",
|
|
845
|
-
error: "Exercise not found or is invalid",
|
|
846
|
-
});
|
|
847
|
-
}
|
|
848
|
-
const nextExercise = syllabusJson.lessons[exerciseIndex + 1] || null;
|
|
1011
|
+
let exercise = syllabus.lessons[exerciseIndex];
|
|
849
1012
|
const exSlug = (0, creatorUtilities_2.slugify)(exercise.id + "-" + exercise.title);
|
|
850
|
-
const readability = (0, creatorUtilities_2.checkReadability)(readme.parsed.content, PARAMS.max_words, 3);
|
|
851
|
-
(0, creatorSocket_1.emitToCourse)(courseSlug, "course-creation", {
|
|
852
|
-
lesson: exSlug,
|
|
853
|
-
status: "generating",
|
|
854
|
-
log: `🔄 The lesson ${exercise.title} has a readability score of ${readability.fkglResult.fkgl}`,
|
|
855
|
-
});
|
|
856
|
-
const exercisesDir = `courses/${courseSlug}/exercises`;
|
|
857
|
-
const targetDir = `${exercisesDir}/${exSlug}`;
|
|
858
|
-
const readmeFilename = `README${(0, creatorUtilities_1.getReadmeExtension)(readme.parsed.language_code)}`;
|
|
859
|
-
await uploadFileToBucket(bucket, readability.newMarkdown, `${targetDir}/${readmeFilename}`);
|
|
860
|
-
if (exercise.type.toLowerCase() === "code" &&
|
|
861
|
-
readme.parsed.codefile_content) {
|
|
862
|
-
(0, creatorSocket_1.emitToCourse)(courseSlug, "course-creation", {
|
|
863
|
-
lesson: exSlug,
|
|
864
|
-
status: "generating",
|
|
865
|
-
log: `🔄 Creating code file for ${exercise.title}`,
|
|
866
|
-
});
|
|
867
|
-
await uploadFileToBucket(bucket, readme.parsed.codefile_content, `${targetDir}/${readme.parsed.codefile_name.toLowerCase().trim()}`);
|
|
868
|
-
(0, creatorSocket_1.emitToCourse)(courseSlug, "course-creation", {
|
|
869
|
-
lesson: exSlug,
|
|
870
|
-
status: "generating",
|
|
871
|
-
log: `✅ Code file created for ${exercise.title}`,
|
|
872
|
-
});
|
|
873
|
-
if (readme.parsed.solution_content) {
|
|
874
|
-
const codeFileName = readme.parsed.codefile_name
|
|
875
|
-
.toLowerCase()
|
|
876
|
-
.trim();
|
|
877
|
-
const solutionFileName = "solution.hide." + codeFileName;
|
|
878
|
-
await uploadFileToBucket(bucket, readme.parsed.solution_content, `${targetDir}/${solutionFileName}`);
|
|
879
|
-
(0, creatorSocket_1.emitToCourse)(courseSlug, "course-creation", {
|
|
880
|
-
lesson: exSlug,
|
|
881
|
-
status: "generating",
|
|
882
|
-
log: `✅ Solution file created for ${exercise.title}`,
|
|
883
|
-
});
|
|
884
|
-
}
|
|
885
|
-
}
|
|
886
|
-
let nextCompletionId = null;
|
|
887
|
-
if (nextExercise &&
|
|
888
|
-
(exerciseIndex === 0 ||
|
|
889
|
-
!(exerciseIndex % 3 === 0) ||
|
|
890
|
-
syllabusJson.generationMode === "continue-with-all")) {
|
|
891
|
-
let feedback = "";
|
|
892
|
-
if (syllabusJson.feedback) {
|
|
893
|
-
feedback = `\n\nThe user added the following feedback with relation to the previous generations: ${syllabusJson.feedback}`;
|
|
894
|
-
}
|
|
895
|
-
nextCompletionId = await startExerciseGeneration(rigoToken, syllabusJson.lessons, syllabusJson.courseInfo, nextExercise, courseSlug, syllabusJson.courseInfo.purpose, readme.parsed.content + "\n\n" + feedback);
|
|
896
|
-
}
|
|
897
|
-
else {
|
|
898
|
-
console.log("Stopping generation process at", exerciseIndex, exercise.title, "because it's a multiple of 3");
|
|
899
|
-
}
|
|
900
|
-
const newSyllabus = Object.assign(Object.assign({}, syllabusJson), { lessons: syllabusJson.lessons.map((lesson, index) => {
|
|
901
|
-
if (index === exerciseIndex) {
|
|
902
|
-
const currentTranslations = lesson.translations || {};
|
|
903
|
-
let currentTranslation = currentTranslations[syllabusJson.courseInfo.language || "en"];
|
|
904
|
-
if (currentTranslation) {
|
|
905
|
-
currentTranslation.completedAt = Date.now();
|
|
906
|
-
}
|
|
907
|
-
else {
|
|
908
|
-
currentTranslation = {
|
|
909
|
-
completionId: readme.id,
|
|
910
|
-
startedAt: Date.now(),
|
|
911
|
-
completedAt: Date.now(),
|
|
912
|
-
};
|
|
913
|
-
}
|
|
914
|
-
currentTranslations[syllabusJson.courseInfo.language || "en"] =
|
|
915
|
-
currentTranslation;
|
|
916
|
-
return Object.assign(Object.assign({}, lesson), { generated: true, status: "DONE", translations: {
|
|
917
|
-
[syllabusJson.courseInfo.language || "en"]: {
|
|
918
|
-
completionId: nextCompletionId,
|
|
919
|
-
completedAt: Date.now(),
|
|
920
|
-
},
|
|
921
|
-
} });
|
|
922
|
-
}
|
|
923
|
-
if (nextExercise &&
|
|
924
|
-
nextExercise.id === lesson.id &&
|
|
925
|
-
nextCompletionId) {
|
|
926
|
-
return Object.assign(Object.assign({}, lesson), { generated: false, status: "GENERATING", translations: {
|
|
927
|
-
[syllabusJson.courseInfo.language || "en"]: {
|
|
928
|
-
completionId: nextCompletionId,
|
|
929
|
-
startedAt: Date.now(),
|
|
930
|
-
},
|
|
931
|
-
} });
|
|
932
|
-
}
|
|
933
|
-
return Object.assign({}, lesson);
|
|
934
|
-
}) });
|
|
935
|
-
console.log("New syllabus", newSyllabus);
|
|
936
|
-
await uploadFileToBucket(bucket, JSON.stringify(newSyllabus), `courses/${courseSlug}/.learn/initialSyllabus.json`);
|
|
937
|
-
(0, creatorSocket_1.emitToCourse)(courseSlug, "course-creation", {
|
|
938
|
-
lesson: exSlug,
|
|
939
|
-
status: "done",
|
|
940
|
-
log: `✅ The lesson ${exercise.id} - ${exercise.title} has been generated successfully!`,
|
|
941
|
-
});
|
|
942
|
-
res.json({ status: "SUCCESS" });
|
|
943
|
-
});
|
|
944
|
-
// Phase 1: Initial content generation webhook
|
|
945
|
-
app.post("/webhooks/:courseSlug/initial-content-processor/:lessonID/:rigoToken", async (req, res) => {
|
|
946
|
-
const { courseSlug, lessonID, rigoToken } = req.params;
|
|
947
|
-
const response = req.body;
|
|
948
|
-
console.log("RECEIVING INITIAL CONTENT WEBHOOK", response);
|
|
949
1013
|
// Handle errors
|
|
950
1014
|
if (response.status === "ERROR") {
|
|
951
|
-
await updateLessonStatusToError(courseSlug,
|
|
1015
|
+
await updateLessonStatusToError(courseSlug, lessonUID, bucket);
|
|
952
1016
|
(0, creatorSocket_1.emitToCourse)(courseSlug, "course-creation", {
|
|
953
|
-
lesson:
|
|
1017
|
+
lesson: exSlug,
|
|
954
1018
|
status: "error",
|
|
955
|
-
log: `❌ Error generating initial content for lesson ${
|
|
1019
|
+
log: `❌ Error generating initial content for lesson ${exSlug}`,
|
|
956
1020
|
});
|
|
957
1021
|
// Retry initial content generation
|
|
958
1022
|
try {
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
completedAt: 0,
|
|
976
|
-
},
|
|
977
|
-
};
|
|
978
|
-
await saveSyllabus(courseSlug, syllabus, bucket);
|
|
979
|
-
}
|
|
1023
|
+
(0, creatorSocket_1.emitToCourse)(courseSlug, "course-creation", {
|
|
1024
|
+
lesson: exSlug,
|
|
1025
|
+
status: "generating",
|
|
1026
|
+
log: `🔄 Retrying initial content generation for lesson ${exSlug}`,
|
|
1027
|
+
});
|
|
1028
|
+
const retryCompletionId = await startInitialContentGeneration(rigoToken, syllabus.lessons, syllabus.courseInfo, exercise, courseSlug, syllabus.courseInfo.purpose, "");
|
|
1029
|
+
// Update lesson status to show it's retrying
|
|
1030
|
+
exercise.status = "GENERATING";
|
|
1031
|
+
exercise.translations = {
|
|
1032
|
+
[syllabus.courseInfo.language || "en"]: {
|
|
1033
|
+
completionId: retryCompletionId,
|
|
1034
|
+
startedAt: Date.now(),
|
|
1035
|
+
completedAt: 0,
|
|
1036
|
+
},
|
|
1037
|
+
};
|
|
1038
|
+
await saveSyllabus(courseSlug, syllabus, bucket);
|
|
980
1039
|
}
|
|
981
1040
|
catch (retryError) {
|
|
982
1041
|
console.error("Error retrying initial content generation:", retryError);
|
|
983
1042
|
(0, creatorSocket_1.emitToCourse)(courseSlug, "course-creation", {
|
|
984
|
-
lesson:
|
|
1043
|
+
lesson: lessonUID,
|
|
985
1044
|
status: "error",
|
|
986
|
-
log: `❌ Failed to retry initial content generation for lesson ${
|
|
1045
|
+
log: `❌ Failed to retry initial content generation for lesson ${lessonUID}`,
|
|
987
1046
|
});
|
|
988
1047
|
}
|
|
989
1048
|
return res.json({ status: "ERROR" });
|
|
990
1049
|
}
|
|
991
1050
|
try {
|
|
992
1051
|
(0, creatorSocket_1.emitToCourse)(courseSlug, "course-creation", {
|
|
993
|
-
lesson:
|
|
1052
|
+
lesson: exSlug,
|
|
994
1053
|
status: "generating",
|
|
995
|
-
log: `✅ Initial content generated for lesson ${
|
|
1054
|
+
log: `✅ Initial content generated for lesson ${exSlug}`,
|
|
996
1055
|
});
|
|
997
1056
|
// Update lesson with initial content
|
|
998
|
-
await updateLessonWithInitialContent(courseSlug,
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1057
|
+
exercise = await updateLessonWithInitialContent(courseSlug, lessonUID, response.parsed, bucket);
|
|
1058
|
+
if (!exercise) {
|
|
1059
|
+
console.error("Exercise not found after updating initial content");
|
|
1060
|
+
return res.json({ status: "ERROR", error: "Exercise not found" });
|
|
1061
|
+
}
|
|
1003
1062
|
let lastLesson = "";
|
|
1004
|
-
const prevLessonIndex =
|
|
1063
|
+
const prevLessonIndex = exerciseIndex - 1;
|
|
1005
1064
|
if (prevLessonIndex >= 0) {
|
|
1006
1065
|
try {
|
|
1007
1066
|
const prevLesson = syllabus.lessons[prevLessonIndex];
|
|
@@ -1015,38 +1074,36 @@ class ServeCommand extends SessionCommand_1.default {
|
|
|
1015
1074
|
console.error("Error searching previous lesson content:", error);
|
|
1016
1075
|
}
|
|
1017
1076
|
}
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
});
|
|
1035
|
-
}
|
|
1077
|
+
const completionId = await startInteractivityGeneration(rigoToken, syllabus.lessons, syllabus.courseInfo, exercise, courseSlug, syllabus.courseInfo.purpose, bucket, lastLesson);
|
|
1078
|
+
// Update lesson status to show it's in Phase 2
|
|
1079
|
+
exercise.status = "GENERATING";
|
|
1080
|
+
exercise.translations = {
|
|
1081
|
+
[syllabus.courseInfo.language || "en"]: {
|
|
1082
|
+
completionId,
|
|
1083
|
+
startedAt: Date.now(),
|
|
1084
|
+
completedAt: 0,
|
|
1085
|
+
},
|
|
1086
|
+
};
|
|
1087
|
+
await saveSyllabus(courseSlug, syllabus, bucket);
|
|
1088
|
+
(0, creatorSocket_1.emitToCourse)(courseSlug, "course-creation", {
|
|
1089
|
+
lesson: exSlug,
|
|
1090
|
+
status: "generating",
|
|
1091
|
+
log: `🔄 Starting interactivity phase for lesson ${exercise.title}`,
|
|
1092
|
+
});
|
|
1036
1093
|
(0, creatorSocket_1.emitToCourse)(courseSlug, "course-creation", {
|
|
1037
|
-
lesson:
|
|
1094
|
+
lesson: exSlug,
|
|
1038
1095
|
status: "initial-content-complete",
|
|
1039
|
-
log: `✅ Initial content generated for lesson ${
|
|
1096
|
+
log: `✅ Initial content generated for lesson ${exSlug}, starting interactivity phase`,
|
|
1040
1097
|
});
|
|
1041
1098
|
res.json({ status: "SUCCESS" });
|
|
1042
1099
|
}
|
|
1043
1100
|
catch (error) {
|
|
1044
1101
|
console.error("Error processing initial content webhook:", error);
|
|
1045
|
-
await updateLessonStatusToError(courseSlug,
|
|
1102
|
+
await updateLessonStatusToError(courseSlug, lessonUID, bucket);
|
|
1046
1103
|
(0, creatorSocket_1.emitToCourse)(courseSlug, "course-creation", {
|
|
1047
|
-
lesson:
|
|
1104
|
+
lesson: exSlug,
|
|
1048
1105
|
status: "error",
|
|
1049
|
-
log: `❌ Error processing initial content for lesson ${
|
|
1106
|
+
log: `❌ Error processing initial content for lesson ${exSlug}`,
|
|
1050
1107
|
});
|
|
1051
1108
|
res
|
|
1052
1109
|
.status(500)
|
|
@@ -1054,28 +1111,30 @@ class ServeCommand extends SessionCommand_1.default {
|
|
|
1054
1111
|
}
|
|
1055
1112
|
});
|
|
1056
1113
|
// Phase 2: Interactivity generation webhook (replaces exercise-processor logic)
|
|
1057
|
-
app.post("/webhooks/:courseSlug/interactivity-processor/:
|
|
1058
|
-
const { courseSlug,
|
|
1114
|
+
app.post("/webhooks/:courseSlug/interactivity-processor/:lessonUID/:rigoToken", async (req, res) => {
|
|
1115
|
+
const { courseSlug, lessonUID, rigoToken } = req.params;
|
|
1059
1116
|
const response = req.body;
|
|
1060
|
-
console.log("RECEIVING INTERACTIVITY WEBHOOK"
|
|
1117
|
+
console.log("RECEIVING INTERACTIVITY WEBHOOK");
|
|
1118
|
+
// console.log("LESSON UID", lessonUID)
|
|
1119
|
+
// console.log("RESPONSE", response)
|
|
1061
1120
|
// Handle errors
|
|
1062
1121
|
if (response.status === "ERROR") {
|
|
1063
|
-
await updateLessonStatusToError(courseSlug,
|
|
1122
|
+
await updateLessonStatusToError(courseSlug, lessonUID, bucket);
|
|
1064
1123
|
(0, creatorSocket_1.emitToCourse)(courseSlug, "course-creation", {
|
|
1065
|
-
lesson:
|
|
1124
|
+
lesson: lessonUID,
|
|
1066
1125
|
status: "error",
|
|
1067
|
-
log: `❌ Error adding interactivity to lesson ${
|
|
1126
|
+
log: `❌ Error adding interactivity to lesson ${lessonUID}`,
|
|
1068
1127
|
});
|
|
1069
1128
|
// Retry interactivity generation
|
|
1070
1129
|
try {
|
|
1071
1130
|
const syllabus = await getSyllabus(courseSlug, bucket);
|
|
1072
|
-
const lessonIndex = syllabus.lessons.findIndex(lesson => lesson.
|
|
1131
|
+
const lessonIndex = syllabus.lessons.findIndex(lesson => lesson.uid === lessonUID);
|
|
1073
1132
|
const exercise = syllabus.lessons[lessonIndex];
|
|
1074
1133
|
if (exercise && exercise.initialContent) {
|
|
1075
1134
|
(0, creatorSocket_1.emitToCourse)(courseSlug, "course-creation", {
|
|
1076
|
-
lesson:
|
|
1135
|
+
lesson: lessonUID,
|
|
1077
1136
|
status: "generating",
|
|
1078
|
-
log: `🔄 Retrying interactivity generation for lesson ${
|
|
1137
|
+
log: `🔄 Retrying interactivity generation for lesson ${lessonUID}`,
|
|
1079
1138
|
});
|
|
1080
1139
|
// Get previous lesson content for context
|
|
1081
1140
|
let lastLesson = "";
|
|
@@ -1108,18 +1167,18 @@ class ServeCommand extends SessionCommand_1.default {
|
|
|
1108
1167
|
catch (retryError) {
|
|
1109
1168
|
console.error("Error retrying interactivity generation:", retryError);
|
|
1110
1169
|
(0, creatorSocket_1.emitToCourse)(courseSlug, "course-creation", {
|
|
1111
|
-
lesson:
|
|
1170
|
+
lesson: lessonUID,
|
|
1112
1171
|
status: "error",
|
|
1113
|
-
log: `❌ Failed to retry interactivity generation for lesson ${
|
|
1172
|
+
log: `❌ Failed to retry interactivity generation for lesson ${lessonUID}`,
|
|
1114
1173
|
});
|
|
1115
1174
|
}
|
|
1116
1175
|
return res.json({ status: "ERROR" });
|
|
1117
1176
|
}
|
|
1118
1177
|
try {
|
|
1119
1178
|
const syllabus = await getSyllabus(courseSlug, bucket);
|
|
1120
|
-
const exerciseIndex = syllabus.lessons.findIndex(lesson => lesson.
|
|
1179
|
+
const exerciseIndex = syllabus.lessons.findIndex(lesson => lesson.uid === lessonUID);
|
|
1121
1180
|
if (exerciseIndex === -1) {
|
|
1122
|
-
console.error("Exercise not found receiving webhook:",
|
|
1181
|
+
console.error("Exercise not found receiving webhook:", lessonUID);
|
|
1123
1182
|
return res.json({ status: "ERROR", error: "Exercise not found" });
|
|
1124
1183
|
}
|
|
1125
1184
|
const exercise = syllabus.lessons[exerciseIndex];
|
|
@@ -1138,35 +1197,6 @@ class ServeCommand extends SessionCommand_1.default {
|
|
|
1138
1197
|
syllabus.courseInfo.language ||
|
|
1139
1198
|
"en")}`;
|
|
1140
1199
|
await uploadFileToBucket(bucket, readability.newMarkdown, `${targetDir}/${readmeFilename}`);
|
|
1141
|
-
// Handle code files if it's a coding exercise
|
|
1142
|
-
if (exercise.type.toLowerCase() === "code" &&
|
|
1143
|
-
response.parsed.codefile_content) {
|
|
1144
|
-
(0, creatorSocket_1.emitToCourse)(courseSlug, "course-creation", {
|
|
1145
|
-
lesson: exSlug,
|
|
1146
|
-
status: "generating",
|
|
1147
|
-
log: `🔄 Creating code file for ${exercise.title}`,
|
|
1148
|
-
});
|
|
1149
|
-
await uploadFileToBucket(bucket, response.parsed.codefile_content, `${targetDir}/${response.parsed.codefile_name
|
|
1150
|
-
.toLowerCase()
|
|
1151
|
-
.trim()}`);
|
|
1152
|
-
(0, creatorSocket_1.emitToCourse)(courseSlug, "course-creation", {
|
|
1153
|
-
lesson: exSlug,
|
|
1154
|
-
status: "generating",
|
|
1155
|
-
log: `✅ Code file created for ${exercise.title}`,
|
|
1156
|
-
});
|
|
1157
|
-
if (response.parsed.solution_content) {
|
|
1158
|
-
const codeFileName = response.parsed.codefile_name
|
|
1159
|
-
.toLowerCase()
|
|
1160
|
-
.trim();
|
|
1161
|
-
const solutionFileName = "solution.hide." + codeFileName;
|
|
1162
|
-
await uploadFileToBucket(bucket, response.parsed.solution_content, `${targetDir}/${solutionFileName}`);
|
|
1163
|
-
(0, creatorSocket_1.emitToCourse)(courseSlug, "course-creation", {
|
|
1164
|
-
lesson: exSlug,
|
|
1165
|
-
status: "generating",
|
|
1166
|
-
log: `✅ Solution file created for ${exercise.title}`,
|
|
1167
|
-
});
|
|
1168
|
-
}
|
|
1169
|
-
}
|
|
1170
1200
|
// Update used components if provided by the AI
|
|
1171
1201
|
if (response.parsed.used_components &&
|
|
1172
1202
|
Array.isArray(response.parsed.used_components)) {
|
|
@@ -1188,11 +1218,11 @@ class ServeCommand extends SessionCommand_1.default {
|
|
|
1188
1218
|
}
|
|
1189
1219
|
catch (error) {
|
|
1190
1220
|
console.error("Error processing interactivity webhook:", error);
|
|
1191
|
-
await updateLessonStatusToError(courseSlug,
|
|
1221
|
+
await updateLessonStatusToError(courseSlug, lessonUID, bucket);
|
|
1192
1222
|
(0, creatorSocket_1.emitToCourse)(courseSlug, "course-creation", {
|
|
1193
|
-
lesson:
|
|
1223
|
+
lesson: lessonUID,
|
|
1194
1224
|
status: "error",
|
|
1195
|
-
log: `❌ Error processing interactivity for lesson ${
|
|
1225
|
+
log: `❌ Error processing interactivity for lesson ${lessonUID}`,
|
|
1196
1226
|
});
|
|
1197
1227
|
res
|
|
1198
1228
|
.status(500)
|
|
@@ -1350,24 +1380,61 @@ class ServeCommand extends SessionCommand_1.default {
|
|
|
1350
1380
|
created,
|
|
1351
1381
|
});
|
|
1352
1382
|
});
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
const
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
.json({ error: "Missing title or readme content" });
|
|
1383
|
+
// Create a new step for a course
|
|
1384
|
+
app.post("/course/:slug/create-step", async (req, res) => {
|
|
1385
|
+
console.log("POST /course/:slug/create-step");
|
|
1386
|
+
const params = req.params;
|
|
1387
|
+
const rigoToken = req.header("x-rigo-token");
|
|
1388
|
+
if (!rigoToken) {
|
|
1389
|
+
return res.status(400).json({ error: "RigoToken not found" });
|
|
1361
1390
|
}
|
|
1362
|
-
const
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
const
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1391
|
+
const { description, stepIndex } = req.body;
|
|
1392
|
+
if (!description) {
|
|
1393
|
+
return res.status(400).json({ error: "Missing description" });
|
|
1394
|
+
}
|
|
1395
|
+
const courseSlug = params.slug;
|
|
1396
|
+
const config = await getConfigJSON(bucket, courseSlug);
|
|
1397
|
+
const initialSyllabus = await getSyllabus(courseSlug, bucket);
|
|
1398
|
+
const stepSlugResponse = await (0, rigoActions_1.generateStepSlug)(rigoToken, {
|
|
1399
|
+
description,
|
|
1400
|
+
stepIndex,
|
|
1401
|
+
courseInfo: JSON.stringify(config),
|
|
1402
|
+
lang: initialSyllabus.courseInfo.language || "en",
|
|
1370
1403
|
});
|
|
1404
|
+
if (stepSlugResponse.status !== "SUCCESS") {
|
|
1405
|
+
return res.status(400).json({ error: stepSlugResponse.status_text });
|
|
1406
|
+
}
|
|
1407
|
+
console.log("STEP SLUG GENERATED BY RIGO", stepSlugResponse);
|
|
1408
|
+
const stepSlug = stepSlugResponse.parsed.slug;
|
|
1409
|
+
// split the slug at the first -
|
|
1410
|
+
const stepId = stepSlug.split("-")[0].trim();
|
|
1411
|
+
const stepTitle = stepSlug.replace(`${stepId}-`, "").trim();
|
|
1412
|
+
const newLesson = {
|
|
1413
|
+
id: stepId,
|
|
1414
|
+
title: stepTitle,
|
|
1415
|
+
description: description,
|
|
1416
|
+
type: "READ",
|
|
1417
|
+
duration: 2,
|
|
1418
|
+
generated: false,
|
|
1419
|
+
status: "GENERATING",
|
|
1420
|
+
initialContent: "",
|
|
1421
|
+
translations: {},
|
|
1422
|
+
uid: stepSlug,
|
|
1423
|
+
};
|
|
1424
|
+
const newLessons = (0, creatorUtilities_1.insertStepInCorrectPosition)(initialSyllabus.lessons, newLesson);
|
|
1425
|
+
// Use new two-phase generation workflow
|
|
1426
|
+
const completionId = await startInitialContentGeneration(rigoToken, newLessons, initialSyllabus.courseInfo, newLesson, courseSlug, initialSyllabus.courseInfo.purpose, "lastResult");
|
|
1427
|
+
newLesson.translations = {
|
|
1428
|
+
[initialSyllabus.courseInfo.language || "en"]: {
|
|
1429
|
+
completionId,
|
|
1430
|
+
startedAt: Date.now(),
|
|
1431
|
+
completedAt: 0,
|
|
1432
|
+
},
|
|
1433
|
+
};
|
|
1434
|
+
await uploadFileToBucket(bucket, JSON.stringify(Object.assign(Object.assign({}, initialSyllabus), { lessons: newLessons })), `courses/${courseSlug}/.learn/initialSyllabus.json`);
|
|
1435
|
+
const targetDir = `courses/${courseSlug}/exercises/${stepSlug}`;
|
|
1436
|
+
await uploadInitialReadme(bucket, stepSlug, targetDir, initialSyllabus.courseInfo);
|
|
1437
|
+
res.json({ status: "SUCCESS", message: "Exercise generati on started!" });
|
|
1371
1438
|
});
|
|
1372
1439
|
app.put("/actions/rename", async (req, res) => {
|
|
1373
1440
|
console.log("PUT /actions/rename");
|