hyungonryu commited on
Commit
0ea4d28
·
verified ·
1 Parent(s): c8c41f3

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +80 -52
app.py CHANGED
@@ -1,40 +1,47 @@
1
  import gradio as gr
2
 
3
- html_code = """
 
 
 
 
 
 
 
4
  <!DOCTYPE html>
5
  <html>
6
  <head>
7
  <meta charset="utf-8">
8
  <title>Video Sync with Custom UI</title>
9
  <style>
10
- body { font-family: sans-serif; margin: 20px; }
11
- table { margin: 0 auto; }
12
- td { padding: 5px; vertical-align: middle; }
13
- .slider, .timeline-slider { }
14
- .video-container-wrapper { position: relative; display: inline-block; }
15
- .video-container {
16
  position: relative;
17
  width: 640px;
18
  height: 480px;
19
  background: #000;
20
  overflow: hidden;
21
- }
22
- .video {
23
  position: absolute;
24
  top: 0;
25
  left: 0;
26
  width: 640px;
27
  height: 480px;
28
  object-fit: cover;
29
- }
30
- .wipe-line {
31
  position: absolute;
32
  top: 0;
33
  width: 2px;
34
  height: 100%;
35
  background: blue;
36
  pointer-events: none;
37
- }
38
  </style>
39
  </head>
40
  <body>
@@ -46,7 +53,11 @@ html_code = """
46
  <tr>
47
  <td width="700">
48
  <font size="1">
49
- This demo video consists of images generated at one-minute intervals from the KMA GK2A satellite's full-disk images, originally captured at ten-minute intervals, using the VFI technique. By using the wipe scrollbar, you can compare the original video (delineated by a blue line) with the enhanced version. You can adjust the zoom and playback speed, and when played at 0.3x speed, the differences between the two videos become distinctly apparent.
 
 
 
 
50
  </font>
51
  </td>
52
  </tr>
@@ -121,8 +132,9 @@ html_code = """
121
  <td colspan="3">
122
  <div class="video-container-wrapper">
123
  <div class="video-container" id="videoContainer">
124
- <video id="video1" class="video" src="video1.mp4" preload="auto" muted></video>
125
- <video id="video2" class="video" src="video2.mp4" preload="auto" muted></video>
 
126
  <div id="wipeLine" class="wipe-line"></div>
127
  </div>
128
  </div>
@@ -134,12 +146,15 @@ html_code = """
134
  // Base width remains constant.
135
  const baseWidth = 640;
136
 
 
 
 
137
  // Predefined video sets.
138
  const videoSets = [
139
- { label: "TongA Case", area: "TongaArea", date: "20220116", sensor: "ir105" },
140
- { label: "SouthAsia", area: "SouthAsia", date: "20240820", sensor: "ir105" },
141
- { label: "EastAsia", area: "EastAsia", date: "20240820", sensor: "ir105" },
142
- { label: "SouthWestAsia", area: "WestAsia", date: "20240820", sensor: "ir105" },
143
  ];
144
 
145
  // Get DOM elements.
@@ -158,60 +173,60 @@ html_code = """
158
  let isPlaying = false;
159
 
160
  // Update playback speed.
161
- function updateSpeed() {
162
  const speedValue = parseFloat(speedSelect.value);
163
  video1.playbackRate = speedValue;
164
  video2.playbackRate = speedValue;
165
- }
166
 
167
  // Update the wipe effect.
168
- function updateWipe() {
169
  const wipeValue = parseFloat(wipeRange.value);
170
  const rightPercent = (1 - wipeValue) * 100;
171
- video2.style.clipPath = `inset(0 ${rightPercent}% 0 0)`;
172
  // Calculate position using the base width.
173
  const lineX = baseWidth * wipeValue - (wipeLine.clientWidth / 2);
174
- wipeLine.style.left = `${lineX}px`;
175
- }
176
 
177
  // Update timeline slider based on video progress.
178
- function updateTimeline() {
179
- if (video1.duration) {
180
  const percent = (video1.currentTime / video1.duration) * 100;
181
  timelineRange.value = percent;
182
- }
183
- }
184
  video1.addEventListener("timeupdate", updateTimeline);
185
 
186
  // Toggle play/pause.
187
- function togglePlayPause() {
188
- if (!isPlaying) {
189
  video1.play();
190
  video2.play();
191
  playPauseBtn.textContent = "Pause";
192
  isPlaying = true;
193
- } else {
194
  video1.pause();
195
  video2.pause();
196
  playPauseBtn.textContent = "Play";
197
  isPlaying = false;
198
- }
199
- }
200
 
201
  // Seek both videos.
202
- function seekTimeline() {
203
- if (video1.duration) {
204
  const percent = timelineRange.value / 100;
205
  const newTime = video1.duration * percent;
206
  video1.currentTime = newTime;
207
  video2.currentTime = newTime;
208
- }
209
- }
210
 
211
  // Update scale and adjust related elements.
212
- function updateScale() {
213
  const scaleValue = parseFloat(scaleSelect.value);
214
- videoContainer.style.transform = `scale(${scaleValue})`;
215
  videoContainer.style.transformOrigin = "top left";
216
  // Update slider and table widths to the visually scaled size.
217
  const effectiveWidth = baseWidth * scaleValue;
@@ -219,29 +234,36 @@ html_code = """
219
  timelineRange.style.width = effectiveWidth + "px";
220
  controlTable.style.width = effectiveWidth + "px";
221
  updateWipe();
222
- }
223
 
224
  // Update video sources based on selected video set.
225
- function updateVideoSet() {
226
  const selectedIndex = videoSetSelect.value;
227
- if (selectedIndex === "") {
228
- // "No" selected, you could reset the video sources if desired.
 
 
 
 
229
  return;
230
- }
231
  const videoSet = videoSets[parseInt(selectedIndex)];
232
  const area = videoSet.area;
233
  const date = videoSet.date;
234
  const sensor = videoSet.sensor;
235
- // Construct filenames.
236
- const originalFile = `${area}/video_${area}_${sensor}um_${date}_10min_010fps.mp4`;
237
- const enhancedFile = `${area}/video_${area}_${sensor}um_${date}_01min_100fps.mp4`;
 
 
238
  // Update video sources.
239
  video1.setAttribute("src", originalFile);
240
  video2.setAttribute("src", enhancedFile);
 
241
  // Reload the videos.
242
  video1.load();
243
  video2.load();
244
- }
245
 
246
  // Event listeners.
247
  playPauseBtn.addEventListener("click", togglePlayPause);
@@ -260,7 +282,13 @@ html_code = """
260
  </html>
261
  """
262
 
263
- with gr.Blocks() as demo:
264
- gr.HTML(html_code)
 
 
 
 
 
265
 
266
- demo.launch()
 
 
1
  import gradio as gr
2
 
3
+ # 1) Your Hugging Face Space name:
4
+ SPACE_USERNAME = "hyungonryu"
5
+ SPACE_NAME = "GoeStationaryVFI"
6
+
7
+ # 2) Base URL for raw MP4 files via "resolve/main":
8
+ BASE_URL = f"https://huggingface.co/spaces/{SPACE_USERNAME}/{SPACE_NAME}/resolve/main"
9
+
10
+ html_code = f"""
11
  <!DOCTYPE html>
12
  <html>
13
  <head>
14
  <meta charset="utf-8">
15
  <title>Video Sync with Custom UI</title>
16
  <style>
17
+ body {{ font-family: sans-serif; margin: 20px; }}
18
+ table {{ margin: 0 auto; }}
19
+ td {{ padding: 5px; vertical-align: middle; }}
20
+ .slider, .timeline-slider {{ }}
21
+ .video-container-wrapper {{ position: relative; display: inline-block; }}
22
+ .video-container {{
23
  position: relative;
24
  width: 640px;
25
  height: 480px;
26
  background: #000;
27
  overflow: hidden;
28
+ }}
29
+ .video {{
30
  position: absolute;
31
  top: 0;
32
  left: 0;
33
  width: 640px;
34
  height: 480px;
35
  object-fit: cover;
36
+ }}
37
+ .wipe-line {{
38
  position: absolute;
39
  top: 0;
40
  width: 2px;
41
  height: 100%;
42
  background: blue;
43
  pointer-events: none;
44
+ }}
45
  </style>
46
  </head>
47
  <body>
 
53
  <tr>
54
  <td width="700">
55
  <font size="1">
56
+ This demo video consists of images generated at one-minute intervals from the KMA GK2A satellite's full-disk images,
57
+ originally captured at ten-minute intervals, using the VFI technique.
58
+ By using the wipe scrollbar, you can compare the original video (delineated by a blue line) with the enhanced version.
59
+ You can adjust the zoom and playback speed, and when played at 0.3x speed, the differences between the two videos
60
+ become distinctly apparent.
61
  </font>
62
  </td>
63
  </tr>
 
132
  <td colspan="3">
133
  <div class="video-container-wrapper">
134
  <div class="video-container" id="videoContainer">
135
+ <!-- Default placeholders -->
136
+ <video id="video1" class="video" src="" preload="auto" muted></video>
137
+ <video id="video2" class="video" src="" preload="auto" muted></video>
138
  <div id="wipeLine" class="wipe-line"></div>
139
  </div>
140
  </div>
 
146
  // Base width remains constant.
147
  const baseWidth = 640;
148
 
149
+ // We'll store the base "resolve/main" URL from Python as a JS var:
150
+ const BASE_URL = "{BASE_URL}";
151
+
152
  // Predefined video sets.
153
  const videoSets = [
154
+ {{ label: "TongA Case", area: "TongaArea", date: "20220116", sensor: "ir105" }},
155
+ {{ label: "SouthAsia", area: "SouthAsia", date: "20240820", sensor: "ir105" }},
156
+ {{ label: "EastAsia", area: "EastAsia", date: "20240820", sensor: "ir105" }},
157
+ {{ label: "SouthWestAsia", area: "WestAsia", date: "20240820", sensor: "ir105" }},
158
  ];
159
 
160
  // Get DOM elements.
 
173
  let isPlaying = false;
174
 
175
  // Update playback speed.
176
+ function updateSpeed() {{
177
  const speedValue = parseFloat(speedSelect.value);
178
  video1.playbackRate = speedValue;
179
  video2.playbackRate = speedValue;
180
+ }}
181
 
182
  // Update the wipe effect.
183
+ function updateWipe() {{
184
  const wipeValue = parseFloat(wipeRange.value);
185
  const rightPercent = (1 - wipeValue) * 100;
186
+ video2.style.clipPath = `inset(0 ${{rightPercent}}% 0 0)`;
187
  // Calculate position using the base width.
188
  const lineX = baseWidth * wipeValue - (wipeLine.clientWidth / 2);
189
+ wipeLine.style.left = `${{lineX}}px`;
190
+ }}
191
 
192
  // Update timeline slider based on video progress.
193
+ function updateTimeline() {{
194
+ if (video1.duration) {{
195
  const percent = (video1.currentTime / video1.duration) * 100;
196
  timelineRange.value = percent;
197
+ }}
198
+ }}
199
  video1.addEventListener("timeupdate", updateTimeline);
200
 
201
  // Toggle play/pause.
202
+ function togglePlayPause() {{
203
+ if (!isPlaying) {{
204
  video1.play();
205
  video2.play();
206
  playPauseBtn.textContent = "Pause";
207
  isPlaying = true;
208
+ }} else {{
209
  video1.pause();
210
  video2.pause();
211
  playPauseBtn.textContent = "Play";
212
  isPlaying = false;
213
+ }}
214
+ }}
215
 
216
  // Seek both videos.
217
+ function seekTimeline() {{
218
+ if (video1.duration) {{
219
  const percent = timelineRange.value / 100;
220
  const newTime = video1.duration * percent;
221
  video1.currentTime = newTime;
222
  video2.currentTime = newTime;
223
+ }}
224
+ }}
225
 
226
  // Update scale and adjust related elements.
227
+ function updateScale() {{
228
  const scaleValue = parseFloat(scaleSelect.value);
229
+ videoContainer.style.transform = `scale(${{scaleValue}})`;
230
  videoContainer.style.transformOrigin = "top left";
231
  // Update slider and table widths to the visually scaled size.
232
  const effectiveWidth = baseWidth * scaleValue;
 
234
  timelineRange.style.width = effectiveWidth + "px";
235
  controlTable.style.width = effectiveWidth + "px";
236
  updateWipe();
237
+ }}
238
 
239
  // Update video sources based on selected video set.
240
+ function updateVideoSet() {{
241
  const selectedIndex = videoSetSelect.value;
242
+ if (selectedIndex === "") {{
243
+ // "No" selected: clear sources or do nothing.
244
+ video1.removeAttribute("src");
245
+ video2.removeAttribute("src");
246
+ video1.load();
247
+ video2.load();
248
  return;
249
+ }}
250
  const videoSet = videoSets[parseInt(selectedIndex)];
251
  const area = videoSet.area;
252
  const date = videoSet.date;
253
  const sensor = videoSet.sensor;
254
+
255
+ // Use "resolve/main" URLs:
256
+ const originalFile = `${{BASE_URL}}/${{area}}/video_${{area}}_${{sensor}}um_${{date}}_10min_010fps.mp4`;
257
+ const enhancedFile = `${{BASE_URL}}/${{area}}/video_${{area}}_${{sensor}}um_${{date}}_01min_100fps.mp4`;
258
+
259
  // Update video sources.
260
  video1.setAttribute("src", originalFile);
261
  video2.setAttribute("src", enhancedFile);
262
+
263
  // Reload the videos.
264
  video1.load();
265
  video2.load();
266
+ }}
267
 
268
  // Event listeners.
269
  playPauseBtn.addEventListener("click", togglePlayPause);
 
282
  </html>
283
  """
284
 
285
+ # Build the Gradio app with just an HTML component.
286
+ def build_app():
287
+ with gr.Blocks() as demo:
288
+ gr.HTML(html_code)
289
+ return demo
290
+
291
+ demo = build_app()
292
 
293
+ if __name__ == "__main__":
294
+ demo.launch()