Spaces:
Configuration error
Configuration error
Dee Ferdinand commited on
Commit ·
410447e
1
Parent(s): f4ac095
feat: init Dee Video Studio — HyperFrames cloud render for testimonial/teaser/trailer videos
Browse files- 4 workflows: testimonial (75s), teaser (30s), trailer (60s), community (60s)
- 6 royalty-free Pixabay music tracks auto-selected by workflow
- WebSocket real-time render progress
- Dark-mode Studio UI with drag-drop upload
- HuggingFace Docker Space ready (port 7860)
- workflows/index.js +92 -0
workflows/index.js
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
function pick(media, preferVideo, idx) {
|
| 2 |
+
const v = media.filter(m => m.mime?.startsWith('video/'));
|
| 3 |
+
const i = media.filter(m => m.mime?.startsWith('image/'));
|
| 4 |
+
const pool = preferVideo ? (v.length ? v : i) : (i.length ? i : v);
|
| 5 |
+
return pool[idx % Math.max(pool.length, 1)] || media[idx % Math.max(media.length, 1)] || null;
|
| 6 |
+
}
|
| 7 |
+
|
| 8 |
+
const testimonial = {
|
| 9 |
+
meta: { name: 'Corporate Testimonial', description: '75s social proof video for corporate AI training.', format: '9:16', duration: 75, music: 'corporate', icon: '🏢' },
|
| 10 |
+
generateCuts(media, cfg) {
|
| 11 |
+
const { clientName = 'AI Training', trainerName = 'Dee Ferdinand' } = cfg;
|
| 12 |
+
return [
|
| 13 |
+
{ start: 0, duration: 3, mediaFile: pick(media, true, 0), caption: clientName ? `${clientName} × AI Training` : 'AI Corporate Training', captionStyle: 'hook' },
|
| 14 |
+
{ start: 3, duration: 2, mediaFile: pick(media, false, 0), caption: `${trainerName} · AI Corporate Trainer`, captionStyle: 'badge' },
|
| 15 |
+
{ start: 5, duration: 5, mediaFile: pick(media, false, 1), caption: '1,000+ professionals trained since 2023', captionStyle: 'stat' },
|
| 16 |
+
{ start: 10, duration: 5, mediaFile: pick(media, true, 1), caption: '80% hands-on · langsung praktek', captionStyle: 'default' },
|
| 17 |
+
{ start: 15, duration: 8, mediaFile: pick(media, true, 2), caption: '"Saya pikir AI itu susah. Ternyata..."', captionStyle: 'default' },
|
| 18 |
+
{ start: 23, duration: 4, mediaFile: pick(media, false, 2), caption: clientName ? `${clientName} · ${new Date().getFullYear()}` : null, captionStyle: 'badge' },
|
| 19 |
+
{ start: 27, duration: 5, mediaFile: pick(media, true, 3), caption: 'Hands-on prompting. Real output.', captionStyle: 'default' },
|
| 20 |
+
{ start: 32, duration: 4, mediaFile: pick(media, false, 3), caption: null },
|
| 21 |
+
{ start: 36, duration: 7, mediaFile: pick(media, true, 4), caption: '"Sekarang saya bisa buat konten sendiri."', captionStyle: 'default' },
|
| 22 |
+
{ start: 43, duration: 4, mediaFile: pick(media, false, 4), caption: null },
|
| 23 |
+
{ start: 47, duration: 8, mediaFile: pick(media, true, 5), caption: 'Energi yang berbeda. Hasil yang nyata.', captionStyle: 'default' },
|
| 24 |
+
{ start: 55, duration: 8, mediaFile: pick(media, true, 0), caption: 'Training AI untuk tim kamu?', captionStyle: 'hook' },
|
| 25 |
+
{ start: 63, duration: 7, mediaFile: pick(media, false, 5), caption: 'DM · atau klik link di bio', captionStyle: 'default' },
|
| 26 |
+
];
|
| 27 |
+
},
|
| 28 |
+
};
|
| 29 |
+
|
| 30 |
+
const teaser = {
|
| 31 |
+
meta: { name: 'Event Teaser', description: '30s fast-cut teaser for upcoming events.', format: '9:16', duration: 30, music: 'energetic', icon: '⚡' },
|
| 32 |
+
generateCuts(media, cfg) {
|
| 33 |
+
const { clientName = 'Next Event' } = cfg;
|
| 34 |
+
const m = media;
|
| 35 |
+
return [
|
| 36 |
+
{ start: 0, duration: 2, mediaFile: pick(m,true,0), caption: 'COMING SOON', captionStyle: 'hook' },
|
| 37 |
+
{ start: 2, duration: 2, mediaFile: pick(m,false,1), caption: null },
|
| 38 |
+
{ start: 4, duration: 2, mediaFile: pick(m,true,1), caption: clientName, captionStyle: 'badge' },
|
| 39 |
+
{ start: 6, duration: 2, mediaFile: pick(m,false,2), caption: null },
|
| 40 |
+
{ start: 8, duration: 2, mediaFile: pick(m,true,2), caption: 'AI Training', captionStyle: 'default' },
|
| 41 |
+
{ start: 10, duration: 2, mediaFile: pick(m,false,3), caption: null },
|
| 42 |
+
{ start: 12, duration: 2, mediaFile: pick(m,true,3), caption: 'Hands-on. Real tools.', captionStyle: 'default' },
|
| 43 |
+
{ start: 14, duration: 3, mediaFile: pick(m,true,0), caption: 'Real results. Real fast.', captionStyle: 'hook' },
|
| 44 |
+
{ start: 17, duration: 3, mediaFile: pick(m,false,4), caption: null },
|
| 45 |
+
{ start: 20, duration: 3, mediaFile: pick(m,true,0), caption: 'Save your spot. Link in bio.', captionStyle: 'default' },
|
| 46 |
+
];
|
| 47 |
+
},
|
| 48 |
+
};
|
| 49 |
+
|
| 50 |
+
const trailer = {
|
| 51 |
+
meta: { name: 'Cinematic Trailer', description: '60s cinematic event recap or brand trailer.', format: '9:16', duration: 60, music: 'cinematic', icon: '🎬' },
|
| 52 |
+
generateCuts(media, cfg) {
|
| 53 |
+
const { clientName = '', trainerName = 'Dee Ferdinand' } = cfg;
|
| 54 |
+
const m = media;
|
| 55 |
+
return [
|
| 56 |
+
{ start: 0, duration: 5, mediaFile: pick(m,true,0), caption: 'Ini bukan teori.', captionStyle: 'hook' },
|
| 57 |
+
{ start: 5, duration: 4, mediaFile: pick(m,false,0), caption: 'Ini yang benar-benar terjadi.', captionStyle: 'default' },
|
| 58 |
+
{ start: 9, duration: 4, mediaFile: pick(m,true,1), caption: clientName || null, captionStyle: 'badge' },
|
| 59 |
+
{ start: 13, duration: 4, mediaFile: pick(m,false,1), caption: null },
|
| 60 |
+
{ start: 17, duration: 5, mediaFile: pick(m,true,2), caption: 'Prompt. Praktek. Hasil.', captionStyle: 'default' },
|
| 61 |
+
{ start: 22, duration: 4, mediaFile: pick(m,false,2), caption: null },
|
| 62 |
+
{ start: 26, duration: 5, mediaFile: pick(m,true,3), caption: '"Saya tidak sangka bisa."', captionStyle: 'default' },
|
| 63 |
+
{ start: 31, duration: 4, mediaFile: pick(m,false,3), caption: null },
|
| 64 |
+
{ start: 35, duration: 5, mediaFile: pick(m,true,0), caption: '1,000+ professionals trained', captionStyle: 'stat' },
|
| 65 |
+
{ start: 40, duration: 5, mediaFile: pick(m,true,4), caption: null },
|
| 66 |
+
{ start: 45, duration: 5, mediaFile: pick(m,false,0), caption: `${trainerName} · AI Corporate Trainer`, captionStyle: 'brand' },
|
| 67 |
+
{ start: 50, duration: 5, mediaFile: pick(m,true,1), caption: 'Training AI untuk tim kamu?', captionStyle: 'hook' },
|
| 68 |
+
];
|
| 69 |
+
},
|
| 70 |
+
};
|
| 71 |
+
|
| 72 |
+
const community = {
|
| 73 |
+
meta: { name: 'Community Story', description: '60s warm documentary for community/church sessions.', format: '9:16', duration: 60, music: 'warm', icon: '🤝' },
|
| 74 |
+
generateCuts(media, cfg) {
|
| 75 |
+
const { clientName = 'Community Training', trainerName = 'Dee Ferdinand' } = cfg;
|
| 76 |
+
const m = media;
|
| 77 |
+
return [
|
| 78 |
+
{ start: 0, duration: 4, mediaFile: pick(m,false,0), caption: 'AI bukan cuma untuk korporat.', captionStyle: 'hook' },
|
| 79 |
+
{ start: 4, duration: 5, mediaFile: pick(m,true,0), caption: clientName, captionStyle: 'badge' },
|
| 80 |
+
{ start: 9, duration: 5, mediaFile: pick(m,false,1), caption: 'Guru. Ibu rumah tangga. Mahasiswa.', captionStyle: 'default' },
|
| 81 |
+
{ start: 14, duration: 5, mediaFile: pick(m,true,1), caption: null },
|
| 82 |
+
{ start: 19, duration: 5, mediaFile: pick(m,false,2), caption: 'Semua orang bisa belajar AI.', captionStyle: 'default' },
|
| 83 |
+
{ start: 24, duration: 8, mediaFile: pick(m,true,2), caption: '"Saya tidak sangka bisa."', captionStyle: 'default' },
|
| 84 |
+
{ start: 32, duration: 5, mediaFile: pick(m,false,3), caption: null },
|
| 85 |
+
{ start: 37, duration: 5, mediaFile: pick(m,true,3), caption: 'Belajar bersama. Tumbuh bersama.', captionStyle: 'default' },
|
| 86 |
+
{ start: 42, duration: 5, mediaFile: pick(m,false,0), caption: `${trainerName} · ${new Date().getFullYear()}`, captionStyle: 'brand' },
|
| 87 |
+
{ start: 47, duration: 5, mediaFile: pick(m,true,0), caption: 'Training AI untuk komunitas kamu?', captionStyle: 'hook' },
|
| 88 |
+
];
|
| 89 |
+
},
|
| 90 |
+
};
|
| 91 |
+
|
| 92 |
+
export const WORKFLOWS = { testimonial, teaser, trailer, community };
|