@learnpack/learnpack 5.0.322 → 5.0.324
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 +94 -23
- package/lib/utils/rigoActions.d.ts +3 -0
- package/lib/utils/rigoActions.js +1 -1
- package/package.json +1 -1
- package/src/commands/serve.ts +123 -31
- package/src/ui/_app/app.css +1 -1
- package/src/ui/_app/app.js +389 -380
- package/src/ui/app.tar.gz +0 -0
- package/src/utils/rigoActions.ts +4 -1
package/lib/commands/serve.js
CHANGED
|
@@ -187,18 +187,32 @@ async function startInitialContentGeneration(rigoToken, steps, packageContext, e
|
|
|
187
187
|
if (!exercise) {
|
|
188
188
|
throw new errorHandler_1.ValidationError("Exercise is required but was not provided");
|
|
189
189
|
}
|
|
190
|
+
console.log("EXERCISE", exercise);
|
|
190
191
|
if (!exercise.id || !exercise.title) {
|
|
191
192
|
throw new errorHandler_1.ValidationError(`Exercise is missing required properties: id=${exercise.id}, title=${exercise.title}`);
|
|
192
193
|
}
|
|
193
194
|
const exSlug = (0, creatorUtilities_2.slugify)(exercise.id + "-" + exercise.title);
|
|
194
195
|
console.log("Starting initial content generation for", exSlug);
|
|
195
196
|
const webhookUrl = `${process.env.HOST}/webhooks/${courseSlug}/initial-content-processor/${exercise.uid}/${rigoToken}`;
|
|
196
|
-
// Determine if this is the first lesson
|
|
197
197
|
const exerciseIndex = steps.findIndex(lesson => lesson.uid === exercise.uid);
|
|
198
198
|
const isFirstLesson = exerciseIndex === 0;
|
|
199
|
-
const
|
|
200
|
-
|
|
201
|
-
|
|
199
|
+
const isLastLesson = exerciseIndex === steps.length - 1;
|
|
200
|
+
let endpointSlug;
|
|
201
|
+
let passTopicDescription = false;
|
|
202
|
+
if (isFirstLesson) {
|
|
203
|
+
endpointSlug = "generate-learnpack-intro-content";
|
|
204
|
+
}
|
|
205
|
+
else if (isLastLesson) {
|
|
206
|
+
endpointSlug = "generate-learnpack-outro-content";
|
|
207
|
+
}
|
|
208
|
+
else if (exercise.id.endsWith(".0")) {
|
|
209
|
+
passTopicDescription = true;
|
|
210
|
+
endpointSlug = "generate-learnpack-topic-intro-content";
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
passTopicDescription = true;
|
|
214
|
+
endpointSlug = "generate-learnpack-subtopic-content";
|
|
215
|
+
}
|
|
202
216
|
// Emit notification that initial content generation is starting
|
|
203
217
|
(0, creatorSocket_1.emitToCourse)(courseSlug, "course-creation", {
|
|
204
218
|
lesson: exSlug,
|
|
@@ -212,12 +226,16 @@ async function startInitialContentGeneration(rigoToken, steps, packageContext, e
|
|
|
212
226
|
// Add random 6-digit number to avoid cache issues
|
|
213
227
|
// eslint-disable-next-line no-mixed-operators
|
|
214
228
|
const randomCacheEvict = Math.floor(100000 + Math.random() * 900000);
|
|
215
|
-
const
|
|
216
|
-
// prev_lesson: lastLesson,
|
|
229
|
+
const inputs = {
|
|
217
230
|
output_language: packageContext.language || "en",
|
|
218
231
|
current_syllabus: JSON.stringify(fullSyllabus),
|
|
219
232
|
lesson_description: JSON.stringify(lessonCleaner(exercise)) + `-${randomCacheEvict}`,
|
|
220
|
-
|
|
233
|
+
target_word_count: String(PARAMS.max_words),
|
|
234
|
+
topic_description: passTopicDescription ?
|
|
235
|
+
String(exercise.description) :
|
|
236
|
+
undefined,
|
|
237
|
+
};
|
|
238
|
+
const res = await (0, rigoActions_1.initialContentGenerator)(rigoToken.trim(), inputs, webhookUrl, endpointSlug);
|
|
221
239
|
console.log("INITIAL CONTENT GENERATOR RES", res);
|
|
222
240
|
return res.id;
|
|
223
241
|
}
|
|
@@ -247,6 +265,7 @@ async function startInteractivityGeneration(rigoToken, steps, packageContext, ex
|
|
|
247
265
|
initial_lesson: exercise.initialContent + `-${randomCacheEvict}`,
|
|
248
266
|
output_language: packageContext.language || "en",
|
|
249
267
|
current_syllabus: JSON.stringify(fullSyllabus),
|
|
268
|
+
lesson_info: JSON.stringify(lessonCleaner(exercise)),
|
|
250
269
|
}, webhookUrl);
|
|
251
270
|
return res.id;
|
|
252
271
|
}
|
|
@@ -1272,6 +1291,12 @@ class ServeCommand extends SessionCommand_1.default {
|
|
|
1272
1291
|
console.log("RECEIVING TRANSLATION WEBHOOK", body);
|
|
1273
1292
|
const readmePath = `courses/${courseSlug}/exercises/${exSlug}/README${(0, creatorUtilities_1.getReadmeExtension)(body.parsed.output_language_code)}`;
|
|
1274
1293
|
await uploadFileToBucket(bucket, body.parsed.translation, readmePath);
|
|
1294
|
+
(0, creatorSocket_1.emitToCourse)(courseSlug, "translation-completed", {
|
|
1295
|
+
exercise: exSlug,
|
|
1296
|
+
language: body.parsed.output_language_code,
|
|
1297
|
+
status: "completed",
|
|
1298
|
+
message: `Translation completed for ${exSlug} to ${body.parsed.output_language_code}`,
|
|
1299
|
+
});
|
|
1275
1300
|
res.json({ status: "SUCCESS" });
|
|
1276
1301
|
});
|
|
1277
1302
|
app.get("/check-preview-image/:slug", async (req, res) => {
|
|
@@ -1513,35 +1538,40 @@ class ServeCommand extends SessionCommand_1.default {
|
|
|
1513
1538
|
}
|
|
1514
1539
|
res.send({ message: "Files renamed" });
|
|
1515
1540
|
});
|
|
1516
|
-
|
|
1517
|
-
console.log("POST /actions/translate");
|
|
1518
|
-
const { exerciseSlugs, languages, rigoToken, currentLanguage } = req.body;
|
|
1519
|
-
const query = req.query;
|
|
1520
|
-
const courseSlug = query.slug;
|
|
1521
|
-
if (!rigoToken) {
|
|
1522
|
-
return res.status(400).json({ error: "RigoToken not found" });
|
|
1523
|
-
}
|
|
1524
|
-
const languagesToTranslate = languages.split(",");
|
|
1525
|
-
const languageCodesRes = await (0, rigoActions_1.getLanguageCodes)(rigoToken, {
|
|
1526
|
-
raw_languages: languagesToTranslate.join(","),
|
|
1527
|
-
});
|
|
1528
|
-
const languageCodes = languageCodesRes.parsed.language_codes;
|
|
1541
|
+
async function processTranslationsAsync(courseSlug, exerciseSlugs, languageCodes, rigoToken, currentLanguage, bucket) {
|
|
1529
1542
|
try {
|
|
1543
|
+
(0, creatorSocket_1.emitToCourse)(courseSlug, "translation-started", {
|
|
1544
|
+
languages: languageCodes,
|
|
1545
|
+
exercises: exerciseSlugs,
|
|
1546
|
+
status: "started",
|
|
1547
|
+
message: "Translation process started",
|
|
1548
|
+
});
|
|
1530
1549
|
await Promise.all(exerciseSlugs.map(async (slug) => {
|
|
1531
1550
|
const readmePath = `courses/${courseSlug}/exercises/${slug}/README${(0, creatorUtilities_1.getReadmeExtension)(currentLanguage)}`;
|
|
1532
1551
|
const readme = await bucket.file(readmePath).download();
|
|
1533
1552
|
await Promise.all(languageCodes.map(async (language) => {
|
|
1534
|
-
// verify if the translation already exists
|
|
1535
1553
|
const translationPath = `courses/${courseSlug}/exercises/${slug}/README${(0, creatorUtilities_1.getReadmeExtension)(language)}`;
|
|
1536
1554
|
const [exists] = await bucket.file(translationPath).exists();
|
|
1537
1555
|
if (exists) {
|
|
1538
1556
|
console.log(`Translation in ${language} already exists for exercise ${slug}`);
|
|
1557
|
+
(0, creatorSocket_1.emitToCourse)(courseSlug, "translation-progress", {
|
|
1558
|
+
exercise: slug,
|
|
1559
|
+
language: language,
|
|
1560
|
+
status: "skipped",
|
|
1561
|
+
message: `Translation in ${language} already exists`,
|
|
1562
|
+
});
|
|
1539
1563
|
return;
|
|
1540
1564
|
}
|
|
1541
1565
|
await (0, rigoActions_1.translateExercise)(rigoToken, {
|
|
1542
1566
|
text_to_translate: readme.toString(),
|
|
1543
1567
|
output_language: language,
|
|
1544
1568
|
}, `${process.env.HOST}/webhooks/${courseSlug}/${slug}/save-translation`);
|
|
1569
|
+
(0, creatorSocket_1.emitToCourse)(courseSlug, "translation-progress", {
|
|
1570
|
+
exercise: slug,
|
|
1571
|
+
language: language,
|
|
1572
|
+
status: "initiated",
|
|
1573
|
+
message: `Translation job initiated for ${slug} to ${language}`,
|
|
1574
|
+
});
|
|
1545
1575
|
}));
|
|
1546
1576
|
}));
|
|
1547
1577
|
const course = await bucket
|
|
@@ -1571,7 +1601,6 @@ class ServeCommand extends SessionCommand_1.default {
|
|
|
1571
1601
|
await uploadFileToBucket(bucket, JSON.stringify(courseJson), `courses/${courseSlug}/learn.json`);
|
|
1572
1602
|
currentLanguages = Object.keys(courseJson.title);
|
|
1573
1603
|
}
|
|
1574
|
-
// Check that all the READMEs exists
|
|
1575
1604
|
const missingReadmeTranslations = [];
|
|
1576
1605
|
let firstAvailable = "";
|
|
1577
1606
|
for (const languageCode of currentLanguages) {
|
|
@@ -1595,7 +1624,49 @@ class ServeCommand extends SessionCommand_1.default {
|
|
|
1595
1624
|
output_language: languageCode,
|
|
1596
1625
|
}, `${process.env.HOST}/webhooks/${courseSlug}/initial-readme-processor`);
|
|
1597
1626
|
}));
|
|
1598
|
-
|
|
1627
|
+
(0, creatorSocket_1.emitToCourse)(courseSlug, "translation-initiated", {
|
|
1628
|
+
status: "completed",
|
|
1629
|
+
message: "All translation jobs have been initiated",
|
|
1630
|
+
languages: languageCodes,
|
|
1631
|
+
exercises: exerciseSlugs,
|
|
1632
|
+
});
|
|
1633
|
+
}
|
|
1634
|
+
catch (error) {
|
|
1635
|
+
console.error("Error processing translations:", error);
|
|
1636
|
+
(0, creatorSocket_1.emitToCourse)(courseSlug, "translation-error", {
|
|
1637
|
+
status: "error",
|
|
1638
|
+
error: error.message,
|
|
1639
|
+
message: "Error occurred during translation processing",
|
|
1640
|
+
});
|
|
1641
|
+
throw error;
|
|
1642
|
+
}
|
|
1643
|
+
}
|
|
1644
|
+
app.post("/actions/translate", express.json(), async (req, res) => {
|
|
1645
|
+
console.log("POST /actions/translate");
|
|
1646
|
+
const { exerciseSlugs, languages, rigoToken, currentLanguage } = req.body;
|
|
1647
|
+
const query = req.query;
|
|
1648
|
+
const courseSlug = typeof query.slug === "string" ? query.slug : undefined;
|
|
1649
|
+
if (!rigoToken) {
|
|
1650
|
+
return res.status(400).json({ error: "RigoToken not found" });
|
|
1651
|
+
}
|
|
1652
|
+
if (!courseSlug) {
|
|
1653
|
+
return res.status(400).json({ error: "Course slug not found" });
|
|
1654
|
+
}
|
|
1655
|
+
const languagesToTranslate = languages.split(",");
|
|
1656
|
+
try {
|
|
1657
|
+
const languageCodesRes = await (0, rigoActions_1.getLanguageCodes)(rigoToken, {
|
|
1658
|
+
raw_languages: languagesToTranslate.join(","),
|
|
1659
|
+
});
|
|
1660
|
+
const languageCodes = languageCodesRes.parsed.language_codes;
|
|
1661
|
+
res.status(200).json({
|
|
1662
|
+
message: "Translation started",
|
|
1663
|
+
languages: languageCodes,
|
|
1664
|
+
exercises: exerciseSlugs,
|
|
1665
|
+
status: "processing",
|
|
1666
|
+
});
|
|
1667
|
+
processTranslationsAsync(courseSlug, exerciseSlugs, languageCodes, rigoToken, currentLanguage, bucket).catch(error => {
|
|
1668
|
+
console.error("Error in background translation processing:", error);
|
|
1669
|
+
});
|
|
1599
1670
|
}
|
|
1600
1671
|
catch (error) {
|
|
1601
1672
|
console.log(error, "ERROR");
|
|
@@ -95,6 +95,8 @@ type TInitialContentGeneratorInputs = {
|
|
|
95
95
|
output_language: string;
|
|
96
96
|
current_syllabus: string;
|
|
97
97
|
lesson_description: string;
|
|
98
|
+
target_word_count: string;
|
|
99
|
+
topic_description?: string;
|
|
98
100
|
};
|
|
99
101
|
export declare const initialContentGenerator: (token: string, inputs: TInitialContentGeneratorInputs, webhookUrl?: string, endpointSlug?: string) => Promise<any>;
|
|
100
102
|
type TAddInteractivityInputs = {
|
|
@@ -102,6 +104,7 @@ type TAddInteractivityInputs = {
|
|
|
102
104
|
prev_lesson: string;
|
|
103
105
|
initial_lesson: string;
|
|
104
106
|
output_language: string;
|
|
107
|
+
lesson_info: string;
|
|
105
108
|
current_syllabus: string;
|
|
106
109
|
};
|
|
107
110
|
export declare const addInteractivity: (token: string, inputs: TAddInteractivityInputs, webhookUrl?: string) => Promise<any>;
|
package/lib/utils/rigoActions.js
CHANGED
|
@@ -306,7 +306,7 @@ const initialContentGenerator = async (token, inputs, webhookUrl, endpointSlug =
|
|
|
306
306
|
exports.initialContentGenerator = initialContentGenerator;
|
|
307
307
|
const addInteractivity = async (token, inputs, webhookUrl) => {
|
|
308
308
|
try {
|
|
309
|
-
const response = await axios_1.default.post(`${api_1.RIGOBOT_HOST}/v1/prompting/completion/lesson-
|
|
309
|
+
const response = await axios_1.default.post(`${api_1.RIGOBOT_HOST}/v1/prompting/completion/add-lesson-interactivy/`, {
|
|
310
310
|
inputs,
|
|
311
311
|
include_purpose_objective: false,
|
|
312
312
|
execute_async: !!webhookUrl,
|
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.324",
|
|
5
5
|
"author": "Alejandro Sanchez @alesanchezr",
|
|
6
6
|
"contributors": [
|
|
7
7
|
{
|
package/src/commands/serve.ts
CHANGED
|
@@ -340,6 +340,8 @@ async function startInitialContentGeneration(
|
|
|
340
340
|
throw new ValidationError("Exercise is required but was not provided")
|
|
341
341
|
}
|
|
342
342
|
|
|
343
|
+
console.log("EXERCISE", exercise)
|
|
344
|
+
|
|
343
345
|
if (!exercise.id || !exercise.title) {
|
|
344
346
|
throw new ValidationError(
|
|
345
347
|
`Exercise is missing required properties: id=${exercise.id}, title=${exercise.title}`
|
|
@@ -351,14 +353,26 @@ async function startInitialContentGeneration(
|
|
|
351
353
|
|
|
352
354
|
const webhookUrl = `${process.env.HOST}/webhooks/${courseSlug}/initial-content-processor/${exercise.uid}/${rigoToken}`
|
|
353
355
|
|
|
354
|
-
// Determine if this is the first lesson
|
|
355
356
|
const exerciseIndex = steps.findIndex(
|
|
356
357
|
lesson => lesson.uid === exercise.uid
|
|
357
358
|
)
|
|
358
359
|
const isFirstLesson = exerciseIndex === 0
|
|
359
|
-
const
|
|
360
|
-
|
|
361
|
-
|
|
360
|
+
const isLastLesson = exerciseIndex === steps.length - 1
|
|
361
|
+
|
|
362
|
+
let endpointSlug: string
|
|
363
|
+
|
|
364
|
+
let passTopicDescription = false
|
|
365
|
+
if (isFirstLesson) {
|
|
366
|
+
endpointSlug = "generate-learnpack-intro-content"
|
|
367
|
+
} else if (isLastLesson) {
|
|
368
|
+
endpointSlug = "generate-learnpack-outro-content"
|
|
369
|
+
} else if (exercise.id.endsWith(".0")) {
|
|
370
|
+
passTopicDescription = true
|
|
371
|
+
endpointSlug = "generate-learnpack-topic-intro-content"
|
|
372
|
+
} else {
|
|
373
|
+
passTopicDescription = true
|
|
374
|
+
endpointSlug = "generate-learnpack-subtopic-content"
|
|
375
|
+
}
|
|
362
376
|
|
|
363
377
|
// Emit notification that initial content generation is starting
|
|
364
378
|
emitToCourse(courseSlug, "course-creation", {
|
|
@@ -376,15 +390,20 @@ async function startInitialContentGeneration(
|
|
|
376
390
|
// eslint-disable-next-line no-mixed-operators
|
|
377
391
|
const randomCacheEvict = Math.floor(100_000 + Math.random() * 900_000)
|
|
378
392
|
|
|
393
|
+
const inputs = {
|
|
394
|
+
output_language: packageContext.language || "en",
|
|
395
|
+
current_syllabus: JSON.stringify(fullSyllabus),
|
|
396
|
+
lesson_description:
|
|
397
|
+
JSON.stringify(lessonCleaner(exercise)) + `-${randomCacheEvict}`,
|
|
398
|
+
target_word_count: String(PARAMS.max_words),
|
|
399
|
+
topic_description: passTopicDescription ?
|
|
400
|
+
String(exercise.description) :
|
|
401
|
+
undefined,
|
|
402
|
+
}
|
|
403
|
+
|
|
379
404
|
const res = await initialContentGenerator(
|
|
380
405
|
rigoToken.trim(),
|
|
381
|
-
|
|
382
|
-
// prev_lesson: lastLesson,
|
|
383
|
-
output_language: packageContext.language || "en",
|
|
384
|
-
current_syllabus: JSON.stringify(fullSyllabus),
|
|
385
|
-
lesson_description:
|
|
386
|
-
JSON.stringify(lessonCleaner(exercise)) + `-${randomCacheEvict}`,
|
|
387
|
-
},
|
|
406
|
+
inputs,
|
|
388
407
|
webhookUrl,
|
|
389
408
|
endpointSlug
|
|
390
409
|
)
|
|
@@ -437,6 +456,7 @@ async function startInteractivityGeneration(
|
|
|
437
456
|
initial_lesson: exercise.initialContent + `-${randomCacheEvict}`,
|
|
438
457
|
output_language: packageContext.language || "en",
|
|
439
458
|
current_syllabus: JSON.stringify(fullSyllabus),
|
|
459
|
+
lesson_info: JSON.stringify(lessonCleaner(exercise)),
|
|
440
460
|
},
|
|
441
461
|
webhookUrl
|
|
442
462
|
)
|
|
@@ -1897,6 +1917,13 @@ export default class ServeCommand extends SessionCommand {
|
|
|
1897
1917
|
|
|
1898
1918
|
await uploadFileToBucket(bucket, body.parsed.translation, readmePath)
|
|
1899
1919
|
|
|
1920
|
+
emitToCourse(courseSlug, "translation-completed", {
|
|
1921
|
+
exercise: exSlug,
|
|
1922
|
+
language: body.parsed.output_language_code,
|
|
1923
|
+
status: "completed",
|
|
1924
|
+
message: `Translation completed for ${exSlug} to ${body.parsed.output_language_code}`,
|
|
1925
|
+
})
|
|
1926
|
+
|
|
1900
1927
|
res.json({ status: "SUCCESS" })
|
|
1901
1928
|
}
|
|
1902
1929
|
)
|
|
@@ -2245,23 +2272,22 @@ export default class ServeCommand extends SessionCommand {
|
|
|
2245
2272
|
res.send({ message: "Files renamed" })
|
|
2246
2273
|
})
|
|
2247
2274
|
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
}
|
|
2257
|
-
|
|
2258
|
-
const languagesToTranslate: string[] = languages.split(",")
|
|
2259
|
-
const languageCodesRes = await getLanguageCodes(rigoToken, {
|
|
2260
|
-
raw_languages: languagesToTranslate.join(","),
|
|
2261
|
-
})
|
|
2262
|
-
const languageCodes = languageCodesRes.parsed.language_codes
|
|
2263
|
-
|
|
2275
|
+
async function processTranslationsAsync(
|
|
2276
|
+
courseSlug: string,
|
|
2277
|
+
exerciseSlugs: string[],
|
|
2278
|
+
languageCodes: string[],
|
|
2279
|
+
rigoToken: string,
|
|
2280
|
+
currentLanguage: string,
|
|
2281
|
+
bucket: Bucket
|
|
2282
|
+
) {
|
|
2264
2283
|
try {
|
|
2284
|
+
emitToCourse(courseSlug, "translation-started", {
|
|
2285
|
+
languages: languageCodes,
|
|
2286
|
+
exercises: exerciseSlugs,
|
|
2287
|
+
status: "started",
|
|
2288
|
+
message: "Translation process started",
|
|
2289
|
+
})
|
|
2290
|
+
|
|
2265
2291
|
await Promise.all(
|
|
2266
2292
|
exerciseSlugs.map(async (slug: string) => {
|
|
2267
2293
|
const readmePath = `courses/${courseSlug}/exercises/${slug}/README${getReadmeExtension(
|
|
@@ -2271,7 +2297,6 @@ export default class ServeCommand extends SessionCommand {
|
|
|
2271
2297
|
|
|
2272
2298
|
await Promise.all(
|
|
2273
2299
|
languageCodes.map(async (language: string) => {
|
|
2274
|
-
// verify if the translation already exists
|
|
2275
2300
|
const translationPath = `courses/${courseSlug}/exercises/${slug}/README${getReadmeExtension(
|
|
2276
2301
|
language
|
|
2277
2302
|
)}`
|
|
@@ -2281,6 +2306,12 @@ export default class ServeCommand extends SessionCommand {
|
|
|
2281
2306
|
console.log(
|
|
2282
2307
|
`Translation in ${language} already exists for exercise ${slug}`
|
|
2283
2308
|
)
|
|
2309
|
+
emitToCourse(courseSlug, "translation-progress", {
|
|
2310
|
+
exercise: slug,
|
|
2311
|
+
language: language,
|
|
2312
|
+
status: "skipped",
|
|
2313
|
+
message: `Translation in ${language} already exists`,
|
|
2314
|
+
})
|
|
2284
2315
|
return
|
|
2285
2316
|
}
|
|
2286
2317
|
|
|
@@ -2292,6 +2323,13 @@ export default class ServeCommand extends SessionCommand {
|
|
|
2292
2323
|
},
|
|
2293
2324
|
`${process.env.HOST}/webhooks/${courseSlug}/${slug}/save-translation`
|
|
2294
2325
|
)
|
|
2326
|
+
|
|
2327
|
+
emitToCourse(courseSlug, "translation-progress", {
|
|
2328
|
+
exercise: slug,
|
|
2329
|
+
language: language,
|
|
2330
|
+
status: "initiated",
|
|
2331
|
+
message: `Translation job initiated for ${slug} to ${language}`,
|
|
2332
|
+
})
|
|
2295
2333
|
})
|
|
2296
2334
|
)
|
|
2297
2335
|
})
|
|
@@ -2339,8 +2377,6 @@ export default class ServeCommand extends SessionCommand {
|
|
|
2339
2377
|
currentLanguages = Object.keys(courseJson.title)
|
|
2340
2378
|
}
|
|
2341
2379
|
|
|
2342
|
-
// Check that all the READMEs exists
|
|
2343
|
-
|
|
2344
2380
|
const missingReadmeTranslations = []
|
|
2345
2381
|
let firstAvailable = ""
|
|
2346
2382
|
for (const languageCode of currentLanguages) {
|
|
@@ -2374,7 +2410,63 @@ export default class ServeCommand extends SessionCommand {
|
|
|
2374
2410
|
})
|
|
2375
2411
|
)
|
|
2376
2412
|
|
|
2377
|
-
|
|
2413
|
+
emitToCourse(courseSlug, "translation-initiated", {
|
|
2414
|
+
status: "completed",
|
|
2415
|
+
message: "All translation jobs have been initiated",
|
|
2416
|
+
languages: languageCodes,
|
|
2417
|
+
exercises: exerciseSlugs,
|
|
2418
|
+
})
|
|
2419
|
+
} catch (error) {
|
|
2420
|
+
console.error("Error processing translations:", error)
|
|
2421
|
+
emitToCourse(courseSlug, "translation-error", {
|
|
2422
|
+
status: "error",
|
|
2423
|
+
error: (error as Error).message,
|
|
2424
|
+
message: "Error occurred during translation processing",
|
|
2425
|
+
})
|
|
2426
|
+
throw error
|
|
2427
|
+
}
|
|
2428
|
+
}
|
|
2429
|
+
|
|
2430
|
+
app.post("/actions/translate", express.json(), async (req, res) => {
|
|
2431
|
+
console.log("POST /actions/translate")
|
|
2432
|
+
const { exerciseSlugs, languages, rigoToken, currentLanguage } = req.body
|
|
2433
|
+
const query = req.query
|
|
2434
|
+
const courseSlug =
|
|
2435
|
+
typeof query.slug === "string" ? query.slug : undefined
|
|
2436
|
+
|
|
2437
|
+
if (!rigoToken) {
|
|
2438
|
+
return res.status(400).json({ error: "RigoToken not found" })
|
|
2439
|
+
}
|
|
2440
|
+
|
|
2441
|
+
if (!courseSlug) {
|
|
2442
|
+
return res.status(400).json({ error: "Course slug not found" })
|
|
2443
|
+
}
|
|
2444
|
+
|
|
2445
|
+
const languagesToTranslate: string[] = languages.split(",")
|
|
2446
|
+
|
|
2447
|
+
try {
|
|
2448
|
+
const languageCodesRes = await getLanguageCodes(rigoToken, {
|
|
2449
|
+
raw_languages: languagesToTranslate.join(","),
|
|
2450
|
+
})
|
|
2451
|
+
const languageCodes = languageCodesRes.parsed.language_codes
|
|
2452
|
+
|
|
2453
|
+
res.status(200).json({
|
|
2454
|
+
message: "Translation started",
|
|
2455
|
+
languages: languageCodes,
|
|
2456
|
+
exercises: exerciseSlugs,
|
|
2457
|
+
status: "processing",
|
|
2458
|
+
})
|
|
2459
|
+
|
|
2460
|
+
processTranslationsAsync(
|
|
2461
|
+
courseSlug,
|
|
2462
|
+
exerciseSlugs,
|
|
2463
|
+
languageCodes,
|
|
2464
|
+
rigoToken,
|
|
2465
|
+
currentLanguage,
|
|
2466
|
+
bucket
|
|
2467
|
+
).catch(error => {
|
|
2468
|
+
console.error("Error in background translation processing:", error)
|
|
2469
|
+
})
|
|
2378
2470
|
} catch (error) {
|
|
2379
2471
|
console.log(error, "ERROR")
|
|
2380
2472
|
return res.status(400).json({ error: (error as Error).message })
|