jakgritb commited on
Commit
dedaa09
·
verified ·
1 Parent(s): 1a29e06

feat: add interactive HF demo clips

Browse files
.gitattributes ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ frontend/public/demo/elevenclip_demo_01.mp4 filter=lfs diff=lfs merge=lfs -text
2
+ frontend/public/demo/elevenclip_demo_02.mp4 filter=lfs diff=lfs merge=lfs -text
3
+ frontend/public/demo/elevenclip_demo_03.mp4 filter=lfs diff=lfs merge=lfs -text
.gitignore CHANGED
@@ -17,6 +17,8 @@ graphify-out/
17
  /tmp/
18
  *.wav
19
  *.mp4
 
 
20
  *.ass
21
  *.log
22
 
 
17
  /tmp/
18
  *.wav
19
  *.mp4
20
+ !frontend/public/demo/
21
+ !frontend/public/demo/*.mp4
22
  *.ass
23
  *.log
24
 
frontend/app/editor/page.tsx CHANGED
@@ -9,7 +9,11 @@ import {
9
  Heart, MessageCircle, Share2, Music,
10
  } from "lucide-react";
11
 
12
- const BBB = "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4";
 
 
 
 
13
 
14
  // ─── Types ────────────────────────────────────────────────────────────────────
15
  type SubEvent = { index: number; text: string; start: number; end: number };
@@ -49,6 +53,7 @@ const L = {
49
  cut: "Cut",
50
  demoSession: "Demo session", waitRender: "Waiting for render", close: "Close",
51
  preview: "PREVIEW",
 
52
  },
53
  th: {
54
  back: "กลับ", clips: "คลิป", clip: "คลิป",
@@ -73,6 +78,7 @@ const L = {
73
  cut: "จุดตัด",
74
  demoSession: "Demo session", waitRender: "รอการเรนเดอร์", close: "ปิด",
75
  preview: "PREVIEW",
 
76
  },
77
  zh: {
78
  back: "返回", clips: "片段", clip: "片段",
@@ -97,6 +103,7 @@ const L = {
97
  cut: "切割",
98
  demoSession: "演示会话", waitRender: "等待渲染", close: "关闭",
99
  preview: "预览",
 
100
  },
101
  } as const;
102
  type Lbl = typeof L[Lang];
@@ -104,48 +111,44 @@ type Lbl = typeof L[Lang];
104
  // ─── Mock data ─────────────────────────────────────────────────────────────────
105
  const MOCK_CLIPS: (ClipResult & { suggested_caption: string })[] = [
106
  {
107
- index: 0, start: 12.5, end: 72.5, duration: 60.0, score: 0.92,
108
- download_url: `${BBB}#t=12,73`, raw_url: BBB, ass_path: "demo_0.ass",
109
- highlight_reason: "High energy moment face detected, audio peak +8.4 dB, Qwen2.5-VL excitement score 0.94",
110
- suggested_caption: "This is why I keep coming back to this stream 🔥 Wait for the ending… #gaming #highlight #viral #amd",
111
  },
112
  {
113
- index: 1, start: 145.0, end: 205.0, duration: 60.0, score: 0.87,
114
- download_url: `${BBB}#t=145,205`, raw_url: BBB, ass_path: "demo_1.ass",
115
- highlight_reason: "Exciting chase sequence Qwen2.5-VL excitement score 0.91, crowd reaction detected at 147.2s",
116
- suggested_caption: "POV: You witness the most insane moment of the year 🎮 Nobody was ready for this #fyp #gaming #moments",
117
  },
118
  {
119
- index: 2, start: 320.0, end: 380.0, duration: 60.0, score: 0.81,
120
- download_url: `${BBB}#t=320,380`, raw_url: BBB, ass_path: "demo_2.ass",
121
- highlight_reason: "Funny reaction moment humor level 0.88, peak audio energy at 320.4s, chat sentiment positive",
122
- suggested_caption: "When the stream becomes a movie 😂 Chat was NOT ready #funny #reaction #viral #clip",
123
  },
124
  ];
125
 
126
  const MOCK_SUBS: Record<number, SubEvent[]> = {
127
  0: [
128
- { index: 0, text: "Let's GO! First blood!", start: 0.0, end: 2.8 },
129
- { index: 1, text: "That was INSANE", start: 3.1, end: 5.5 },
130
- { index: 2, text: "No way he survived that", start: 6.0, end: 8.4 },
131
- { index: 3, text: "Triple kill right there", start: 9.0, end: 11.2 },
132
- { index: 4, text: "Chat is going crazy right now", start: 12.0, end: 14.8 },
133
- { index: 5, text: "This is the best clip of the stream", start: 55.0, end: 58.5 },
134
  ],
135
  1: [
136
- { index: 0, text: "Oh my god, this part...", start: 0.0, end: 3.0 },
137
- { index: 1, text: "I've been waiting for this moment", start: 3.4, end: 6.0 },
138
- { index: 2, text: "HERE WE GO", start: 7.0, end: 9.0 },
139
- { index: 3, text: "The crowd is going wild", start: 28.0, end: 31.0 },
140
- { index: 4, text: "YESSS! FINALLY!", start: 54.0, end: 57.0 },
141
- { index: 5, text: "We are SO back", start: 57.5, end: 60.0 },
142
  ],
143
  2: [
144
- { index: 0, text: "Chat predicted this would happen", start: 0.0, end: 2.5 },
145
- { index: 1, text: "I cannot believe this is real", start: 3.0, end: 6.2 },
146
- { index: 2, text: "This is why I stream every day", start: 7.0, end: 9.5 },
147
- { index: 3, text: "No script. This is 100% real.", start: 10.0, end: 13.0 },
148
- { index: 4, text: "Clip it. Someone clip this.", start: 50.0, end: 53.0 },
149
  ],
150
  };
151
 
@@ -469,7 +472,9 @@ function EditorContent() {
469
  const clip = clips[activeClip];
470
  const apiBase = process.env.NEXT_PUBLIC_API_URL || "http://localhost:8000";
471
  const rawUrl = clip ? (downloadUrls[clip.index] ?? clip.download_url) : "";
472
- const clipDownloadUrl = rawUrl.startsWith("http") ? rawUrl : rawUrl ? `${apiBase}${rawUrl}` : "";
 
 
473
  const suggestedCaption = (clip as (typeof clip & { suggested_caption?: string }))?.suggested_caption;
474
  const currentCuts = clip ? (cutRegions[clip.index] ?? []) : [];
475
  const clipDuration = clip ? clip.duration + (trimEnd[clip.index] ?? 0) - (trimStart[clip.index] ?? 0) : 60;
@@ -511,6 +516,11 @@ function EditorContent() {
511
  </span>
512
  </div>
513
  </nav>
 
 
 
 
 
514
 
515
  {/* ── Main layout ── */}
516
  <div className="flex flex-1 min-h-0 overflow-hidden">
 
9
  Heart, MessageCircle, Share2, Music,
10
  } from "lucide-react";
11
 
12
+ const DEMO_CLIP_URLS = [
13
+ "/demo/elevenclip_demo_01.mp4",
14
+ "/demo/elevenclip_demo_02.mp4",
15
+ "/demo/elevenclip_demo_03.mp4",
16
+ ];
17
 
18
  // ─── Types ────────────────────────────────────────────────────────────────────
19
  type SubEvent = { index: number; text: string; start: number; end: number };
 
53
  cut: "Cut",
54
  demoSession: "Demo session", waitRender: "Waiting for render", close: "Close",
55
  preview: "PREVIEW",
56
+ demoNotice: "Simulation only — these are pre-rendered demo results, not a live GPU run.",
57
  },
58
  th: {
59
  back: "กลับ", clips: "คลิป", clip: "คลิป",
 
78
  cut: "จุดตัด",
79
  demoSession: "Demo session", waitRender: "รอการเรนเดอร์", close: "ปิด",
80
  preview: "PREVIEW",
81
+ demoNotice: "โหมดจำลองเท่านั้น — คลิปเหล่านี้เป็นผลลัพธ์ที่เตรียมไว้ ไม่ได้รัน GPU สด",
82
  },
83
  zh: {
84
  back: "返回", clips: "片段", clip: "片段",
 
103
  cut: "切割",
104
  demoSession: "演示会话", waitRender: "等待渲染", close: "关闭",
105
  preview: "预览",
106
+ demoNotice: "仅为模拟演示 — 这些是预渲染结果,并非实时 GPU 运行。",
107
  },
108
  } as const;
109
  type Lbl = typeof L[Lang];
 
111
  // ─── Mock data ─────────────────────────────────────────────────────────────────
112
  const MOCK_CLIPS: (ClipResult & { suggested_caption: string })[] = [
113
  {
114
+ index: 0, start: 13.0, end: 43.0, duration: 30.0, score: 0.462,
115
+ download_url: DEMO_CLIP_URLS[0], raw_url: DEMO_CLIP_URLS[0], ass_path: "demo_0.ass",
116
+ highlight_reason: "The speaker is enthusiastically discussing the benefits of the AMD Instinct MI350P, making it a compelling highlight for tech enthusiasts.",
117
+ suggested_caption: "AMD Instinct MI350P explained in 30 seconds: AI infrastructure, performance, and enterprise-ready acceleration.",
118
  },
119
  {
120
+ index: 1, start: 125.0, end: 155.0, duration: 30.0, score: 0.45,
121
+ download_url: DEMO_CLIP_URLS[1], raw_url: DEMO_CLIP_URLS[1], ass_path: "demo_1.ass",
122
+ highlight_reason: "The speaker is enthusiastically discussing the benefits of the AMD Instinct MI350P, making it engaging for viewers interested in technology and AI.",
123
+ suggested_caption: "A quick look at how AMD Instinct GPUs power modern AI and high-performance computing workloads.",
124
  },
125
  {
126
+ index: 2, start: 149.0, end: 179.0, duration: 30.0, score: 0.398,
127
+ download_url: DEMO_CLIP_URLS[2], raw_url: DEMO_CLIP_URLS[2], ass_path: "demo_2.ass",
128
+ highlight_reason: "The speaker is enthusiastically discussing the benefits of the AMD Instinct MI350P, making it engaging for viewers interested in enterprise computing and AI.",
129
+ suggested_caption: "Enterprise AI needs serious compute. This clip highlights where AMD Instinct fits in the stack.",
130
  },
131
  ];
132
 
133
  const MOCK_SUBS: Record<number, SubEvent[]> = {
134
  0: [
135
+ { index: 0, text: "AMD Instinct MI350P", start: 0.0, end: 2.8 },
136
+ { index: 1, text: "Built for AI acceleration", start: 3.2, end: 5.8 },
137
+ { index: 2, text: "Enterprise compute at scale", start: 7.0, end: 9.6 },
138
+ { index: 3, text: "Vision, audio, and transcript signals combined", start: 12.0, end: 15.0 },
139
+ { index: 4, text: "HRE keeps the important subject visible", start: 20.0, end: 23.4 },
 
140
  ],
141
  1: [
142
+ { index: 0, text: "The key benefit is throughput", start: 0.0, end: 2.8 },
143
+ { index: 1, text: "AI workloads need memory and bandwidth", start: 3.4, end: 6.3 },
144
+ { index: 2, text: "Qwen selected this as a strong technical moment", start: 8.0, end: 11.2 },
145
+ { index: 3, text: "Captions can be edited in the demo", start: 18.0, end: 21.0 },
 
 
146
  ],
147
  2: [
148
+ { index: 0, text: "Enterprise AI infrastructure", start: 0.0, end: 2.7 },
149
+ { index: 1, text: "The model chooses the most useful 30 seconds", start: 4.0, end: 7.2 },
150
+ { index: 2, text: "Zoom and caption style vary by moment", start: 9.0, end: 12.0 },
151
+ { index: 3, text: "This preview uses pre-rendered demo output", start: 20.0, end: 23.0 },
 
152
  ],
153
  };
154
 
 
472
  const clip = clips[activeClip];
473
  const apiBase = process.env.NEXT_PUBLIC_API_URL || "http://localhost:8000";
474
  const rawUrl = clip ? (downloadUrls[clip.index] ?? clip.download_url) : "";
475
+ const clipDownloadUrl = isDemo
476
+ ? rawUrl
477
+ : rawUrl.startsWith("http") ? rawUrl : rawUrl ? `${apiBase}${rawUrl}` : "";
478
  const suggestedCaption = (clip as (typeof clip & { suggested_caption?: string }))?.suggested_caption;
479
  const currentCuts = clip ? (cutRegions[clip.index] ?? []) : [];
480
  const clipDuration = clip ? clip.duration + (trimEnd[clip.index] ?? 0) - (trimStart[clip.index] ?? 0) : 60;
 
516
  </span>
517
  </div>
518
  </nav>
519
+ {isDemo && (
520
+ <div className="border-b border-cyan-400/20 bg-cyan-400/10 px-5 py-2 text-center text-xs text-cyan-100">
521
+ {lbl.demoNotice}
522
+ </div>
523
+ )}
524
 
525
  {/* ── Main layout ── */}
526
  <div className="flex flex-1 min-h-0 overflow-hidden">
frontend/app/page.tsx CHANGED
@@ -28,6 +28,7 @@ const T = {
28
  generateHRE: "Generate with HRE",
29
  tryDemo: "Try Demo",
30
  demoHint: "Demo mode — works without backend",
 
31
  accessRequired: "Enter the demo access code to run real GPU generation.",
32
  hackathon: "AMD Developer Hackathon 2026 · Track 3: Vision & Multimodal AI",
33
  },
@@ -44,6 +45,7 @@ const T = {
44
  generateHRE: "สร้างด้วย HRE",
45
  tryDemo: "ลองดูตัวอย่าง",
46
  demoHint: "โหมด Demo — ไม่ต้องเชื่อม backend",
 
47
  accessRequired: "ใส่รหัสเดโมก่อน เพื่อรันของจริงบน GPU",
48
  hackathon: "AMD Developer Hackathon 2026 · Track 3: Vision & Multimodal AI",
49
  },
@@ -60,6 +62,7 @@ const T = {
60
  generateHRE: "HRE 生成",
61
  tryDemo: "试用演示",
62
  demoHint: "演示模式 — 无需后端连接",
 
63
  accessRequired: "请输入演示访问码以运行真实 GPU 生成。",
64
  hackathon: "AMD Developer Hackathon 2026 · Track 3: Vision & Multimodal AI",
65
  },
@@ -81,14 +84,14 @@ const FONT_MAP: Record<string, string> = {
81
  };
82
 
83
  const DEMO_STAGES = [
84
- { stage: "download", pct: 10, message: "Fetching sample video (yt-dlp)..." },
85
- { stage: "audio", pct: 22, message: "Extracting audio track..." },
86
- { stage: "scenes", pct: 35, message: "PySceneDetect24 scenes found" },
87
- { stage: "transcribe",pct: 50, message: "Whisper ROCm — transcribing 3m 42s..." },
88
- { stage: "vision", pct: 65, message: "Qwen2.5-VL analyzing frames + transcript..." },
89
- { stage: "scoring", pct: 80, message: "score = 0.4×vision + 0.35×audio + 0.25×text" },
90
- { stage: "cutting", pct: 90, message: "Cutting 3 highlight clips via ffmpeg-amf..." },
91
- { stage: "subtitles", pct: 96, message: "Generating ASS subtitles (pysubs2)..." },
92
  { stage: "done", pct: 100, message: "" },
93
  ];
94
 
@@ -116,6 +119,7 @@ export default function HomePage() {
116
 
117
  const [step, setStep] = useState<Step>(1);
118
  const [videoFile, setVideoFile] = useState<File | null>(null);
 
119
  const [channelDesc, setChannelDesc] = useState("");
120
 
121
  const [clipSettings, setClipSettings] = useState({
@@ -153,7 +157,7 @@ export default function HomePage() {
153
  const wsRef = useRef<WebSocket | null>(null);
154
  const demoTimerRef = useRef<ReturnType<typeof setInterval> | null>(null);
155
 
156
- const canProceedStep1 = !!videoFile;
157
 
158
  useEffect(() => {
159
  const font = FONT_MAP[clipSettings.subtitle_language] ?? "Noto Sans";
@@ -183,6 +187,10 @@ export default function HomePage() {
183
  const handleGenerate = async () => {
184
  if (!canProceedStep1) return;
185
  setStep("generating");
 
 
 
 
186
  if (DEMO_ONLY_PUBLIC && !accessCode.trim()) {
187
  setProgress({ stage: "error", pct: 0, message: t.accessRequired });
188
  return;
@@ -226,45 +234,18 @@ export default function HomePage() {
226
  };
227
 
228
  const handleDemo = async () => {
229
- setStep("generating");
230
- if (DEMO_ONLY_PUBLIC && !accessCode.trim()) {
231
- runMockDemo();
232
- return;
233
- }
234
- try {
235
- const settings: ProcessSettings = {
236
- use_demo_video: true,
237
- channel_description: "Gaming and reaction channel with funny moments",
238
- clip_style: "funny",
239
- target_duration: 60,
240
- clip_count: 3,
241
- clip_language: "auto",
242
- subtitle_language: "english",
243
- mode: "hre",
244
- style_config: {},
245
- };
246
- const sessionId = await startProcessing(settings, undefined, accessCode);
247
- localStorage.setItem("elevnclip_session", sessionId);
248
-
249
- const ws = connectProgressWS(sessionId, (data) => {
250
- setProgress(data);
251
- if (data.stage === "done") { ws.close(); router.push(`/editor?session=${sessionId}`); }
252
- if (data.stage === "error") ws.close();
253
- });
254
- wsRef.current = ws;
255
-
256
- const poll = setInterval(async () => {
257
- try {
258
- const data = await getClips(sessionId);
259
- if (data.last_progress) setProgress(data.last_progress);
260
- if (data.status === "done") { clearInterval(poll); router.push(`/editor?session=${sessionId}`); }
261
- if (data.status === "error") clearInterval(poll);
262
- } catch { /* ignore */ }
263
- }, 3000);
264
- setTimeout(() => clearInterval(poll), 600_000);
265
- } catch {
266
- runMockDemo();
267
- }
268
  };
269
 
270
  return (
@@ -330,11 +311,17 @@ export default function HomePage() {
330
  )}
331
 
332
  <div className="bg-white/5 border border-white/10 rounded-2xl p-5 backdrop-blur-sm flex-1 min-h-0 overflow-y-auto flex flex-col">
 
 
 
 
 
 
333
  {step === 1 && (
334
  <>
335
  <h2 className="text-lg font-semibold mb-4">{t.addVideo}</h2>
336
  <VideoUpload
337
- onFileSelect={(f) => setVideoFile(f)}
338
  onChannelDesc={setChannelDesc}
339
  channelDesc={channelDesc}
340
  accessCode={accessCode}
 
28
  generateHRE: "Generate with HRE",
29
  tryDemo: "Try Demo",
30
  demoHint: "Demo mode — works without backend",
31
+ demoNotice: "Demo simulation: you can change settings and walk through the real flow, but generation uses pre-rendered ElevenClip AI results.",
32
  accessRequired: "Enter the demo access code to run real GPU generation.",
33
  hackathon: "AMD Developer Hackathon 2026 · Track 3: Vision & Multimodal AI",
34
  },
 
45
  generateHRE: "สร้างด้วย HRE",
46
  tryDemo: "ลองดูตัวอย่าง",
47
  demoHint: "โหมด Demo — ไม่ต้องเชื่อม backend",
48
+ demoNotice: "โหมดจำลอง: ปรับตั้งค่าและลองกดตาม flow จริงได้ แต่ผลลัพธ์ใช้คลิป ElevenClip AI ที่เราสร้างไว้แล้ว",
49
  accessRequired: "ใส่รหัสเดโมก่อน เพื่อรันของจริงบน GPU",
50
  hackathon: "AMD Developer Hackathon 2026 · Track 3: Vision & Multimodal AI",
51
  },
 
62
  generateHRE: "HRE 生成",
63
  tryDemo: "试用演示",
64
  demoHint: "演示模式 — 无需后端连接",
65
+ demoNotice: "模拟演示:可以调整设置并体验真实流程,但生成结果使用预先渲染的 ElevenClip AI 片段。",
66
  accessRequired: "请输入演示访问码以运行真实 GPU 生成。",
67
  hackathon: "AMD Developer Hackathon 2026 · Track 3: Vision & Multimodal AI",
68
  },
 
84
  };
85
 
86
  const DEMO_STAGES = [
87
+ { stage: "download", pct: 10, message: "Demo simulation loading the AMD Instinct source video..." },
88
+ { stage: "audio", pct: 22, message: "Simulating audio extraction and speech alignment..." },
89
+ { stage: "scenes", pct: 35, message: "Simulating scene detection strongest moments selected" },
90
+ { stage: "transcribe",pct: 50, message: "Simulating Whisper transcript timing..." },
91
+ { stage: "vision", pct: 65, message: "Simulating Qwen2.5-VL multimodal analysis..." },
92
+ { stage: "scoring", pct: 80, message: "Simulating highlight scoring and HRE edit planning..." },
93
+ { stage: "cutting", pct: 90, message: "Loading 3 pre-rendered ElevenClip AI demo clips..." },
94
+ { stage: "subtitles", pct: 96, message: "Preparing interactive editor preview..." },
95
  { stage: "done", pct: 100, message: "" },
96
  ];
97
 
 
119
 
120
  const [step, setStep] = useState<Step>(1);
121
  const [videoFile, setVideoFile] = useState<File | null>(null);
122
+ const [demoMode, setDemoMode] = useState(false);
123
  const [channelDesc, setChannelDesc] = useState("");
124
 
125
  const [clipSettings, setClipSettings] = useState({
 
157
  const wsRef = useRef<WebSocket | null>(null);
158
  const demoTimerRef = useRef<ReturnType<typeof setInterval> | null>(null);
159
 
160
+ const canProceedStep1 = demoMode || !!videoFile;
161
 
162
  useEffect(() => {
163
  const font = FONT_MAP[clipSettings.subtitle_language] ?? "Noto Sans";
 
187
  const handleGenerate = async () => {
188
  if (!canProceedStep1) return;
189
  setStep("generating");
190
+ if (demoMode) {
191
+ runMockDemo();
192
+ return;
193
+ }
194
  if (DEMO_ONLY_PUBLIC && !accessCode.trim()) {
195
  setProgress({ stage: "error", pct: 0, message: t.accessRequired });
196
  return;
 
234
  };
235
 
236
  const handleDemo = async () => {
237
+ setDemoMode(true);
238
+ setVideoFile(null);
239
+ setChannelDesc("AMD Instinct product video for AI, HPC, and enterprise computing audiences");
240
+ setClipSettings({
241
+ clip_style: "educational",
242
+ target_duration: 30,
243
+ clip_count: 3,
244
+ clip_language: "auto",
245
+ subtitle_language: "english",
246
+ mode: "hre",
247
+ });
248
+ setStep(2);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
249
  };
250
 
251
  return (
 
311
  )}
312
 
313
  <div className="bg-white/5 border border-white/10 rounded-2xl p-5 backdrop-blur-sm flex-1 min-h-0 overflow-y-auto flex flex-col">
314
+ {demoMode && step !== "generating" && (
315
+ <div className="mb-4 rounded-xl border border-cyan-400/25 bg-cyan-400/10 px-4 py-3 text-sm text-cyan-100">
316
+ {t.demoNotice}
317
+ </div>
318
+ )}
319
+
320
  {step === 1 && (
321
  <>
322
  <h2 className="text-lg font-semibold mb-4">{t.addVideo}</h2>
323
  <VideoUpload
324
+ onFileSelect={(f) => { setDemoMode(false); setVideoFile(f); }}
325
  onChannelDesc={setChannelDesc}
326
  channelDesc={channelDesc}
327
  accessCode={accessCode}
frontend/next-env.d.ts CHANGED
@@ -1,6 +1,6 @@
1
  /// <reference types="next" />
2
  /// <reference types="next/image-types/global" />
3
- import "./.next/dev/types/routes.d.ts";
4
 
5
  // NOTE: This file should not be edited
6
  // see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
 
1
  /// <reference types="next" />
2
  /// <reference types="next/image-types/global" />
3
+ import "./.next/types/routes.d.ts";
4
 
5
  // NOTE: This file should not be edited
6
  // see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
frontend/public/demo/elevenclip_demo_01.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:eef8a018ca69c935728a6752288dce0d5a44aa255237728e1d22a45af09d383a
3
+ size 13201340
frontend/public/demo/elevenclip_demo_02.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:cbbcf2d951ed4d058281812ca82843ddd35a35c03cbb08c9911ee86ce345b78b
3
+ size 12197380
frontend/public/demo/elevenclip_demo_03.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:584a72575f255953d27c18db1723c0e3b53b309908be715db6a9cb1c9ae63b78
3
+ size 11542882