Download apps/api/src/scripts/audit-inventory.ts from safetrack/edtech: direct link, hf CLI and curl.
- Browser
- Download file 3.59 kB
-
https://huggingface.co/spaces/safetrack/edtech/resolve/main/apps/api/src/scripts/audit-inventory.ts
- Command line
-
hf download hf://spaces/safetrack/edtech/apps/api/src/scripts/audit-inventory.ts
-
curl -L -o audit-inventory.ts https://huggingface.co/spaces/safetrack/edtech/resolve/main/apps/api/src/scripts/audit-inventory.ts
3.59 kB
| import { PrismaClient } from '@prisma/client'; | |
| const prisma = new PrismaClient(); | |
| async function runAudit() { | |
| console.log("๐ Starting XAMLร V1 Inventory Audit..."); | |
| console.log("=========================================="); | |
| const tracks = await prisma.track.findMany({ | |
| include: { | |
| days: { | |
| orderBy: { dayNumber: 'asc' } | |
| } | |
| } | |
| }); | |
| const report: { | |
| secteur: string; | |
| lang: string; | |
| day: number; | |
| errors: string[] | |
| }[] = []; | |
| // Group tracks by "Secteur" intuitively from title or id (e.g. T1-FR -> T1 is not a sector maybe?) | |
| // Actually the user mentioned "Couture", "Restauration", so these might be in track titles! | |
| for (const track of tracks) { | |
| // Find language | |
| const lang = track.language || (track.id.endsWith('-WO') ? 'WOLOF' : 'FR'); | |
| for (const day of track.days) { | |
| const errors: string[] = []; | |
| // 1. Audio check | |
| if (lang === 'WOLOF' && !day.audioUrl) { | |
| errors.push("๐ต Missing Audio (Required for Wolof)"); | |
| } | |
| // 2. Visual check | |
| if (!day.imageUrl && !day.videoUrl) { | |
| errors.push("๐ผ๏ธ Missing Visual (Image or Video absent)"); | |
| } | |
| // 3. Multilingual JSON Validation | |
| // Let's check buttonsJson or criteria to see if it's explicitly malformed | |
| if (day.buttonsJson) { | |
| try { | |
| // const parsed = typeof day.buttonsJson === 'string' ? JSON.parse(day.buttonsJson) : day.buttonsJson; | |
| // If parsed is not fine, it will throw | |
| } catch (e) { | |
| errors.push("โ ๏ธ Invalid Multilingual JSON (corrupted buttonsJson)"); | |
| } | |
| } | |
| // 4. Pitch Deck Validation on Day 12 | |
| if (day.dayNumber === 12) { | |
| let hasPitchTrigger = false; | |
| // Check if badges include PITCH_DECK or exerciseType is FINAL, or buttonsJson has specific trigger | |
| if (day.badges && JSON.stringify(day.badges).includes("PITCH_DECK")) hasPitchTrigger = true; | |
| if (day.badges && JSON.stringify(day.badges).includes("PITCH_AI")) hasPitchTrigger = true; | |
| if (day.badges && JSON.stringify(day.badges).includes("DOCUMENT")) hasPitchTrigger = true; | |
| if (JSON.stringify(day.buttonsJson || "").includes("DOCUMENT_GENERATION")) hasPitchTrigger = true; | |
| if (!hasPitchTrigger) { | |
| // Let's record metadata found to help debug | |
| errors.push(`๐ Pitch Deck Metadata (end of track) missing (Badges: ${JSON.stringify(day.badges)})`); | |
| } | |
| } | |
| if (errors.length > 0) { | |
| report.push({ | |
| secteur: track.title, | |
| lang, | |
| day: day.dayNumber, | |
| errors | |
| }); | |
| } | |
| } | |
| } | |
| console.log(`\n๐ SCAN RESULT: ${report.length} issues found.\n`); | |
| // Print Table format | |
| for (const item of report) { | |
| console.log(`[${item.lang}] ${item.secteur} - Day ${item.day}:`); | |
| item.errors.forEach(err => console.log(` โ ${err}`)); | |
| console.log("-".repeat(40)); | |
| } | |
| if (report.length === 0) { | |
| console.log("โ Audit Perfect! All tracks are complete and ready for V1."); | |
| } | |
| await prisma.$disconnect(); | |
| } | |
| runAudit().catch(e => { | |
| console.error(e); | |
| process.exit(1); | |
| }); | |