Athspi commited on
Commit
c84a6da
·
verified ·
1 Parent(s): 08c3547

Update templates/index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +73 -120
templates/index.html CHANGED
@@ -5,7 +5,7 @@
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
  <title>AI Video Narrator</title>
7
  <style>
8
- @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap');
9
 
10
  :root {
11
  --primary-color: #0d6efd;
@@ -14,116 +14,55 @@
14
  --card-background: #ffffff;
15
  --heading-color: #212529;
16
  --border-color: #dee2e6;
17
- --shadow: 0 8px 30px rgba(0,0,0,0.1);
18
- }
19
-
20
- *, *::before, *::after {
21
- box-sizing: border-box;
22
  }
23
 
 
24
  body {
25
- font-family: 'Inter', sans-serif;
26
- margin: 0;
27
- background-color: var(--background-color);
28
- display: flex;
29
- justify-content: center;
30
- align-items: flex-start;
31
- padding: 2rem;
32
- min-height: 100vh;
33
  }
34
  .container {
35
- background-color: var(--card-background);
36
- padding: 2.5rem 3rem;
37
- border-radius: 20px;
38
- border: 1px solid var(--border-color);
39
- box-shadow: var(--shadow);
40
- width: 100%;
41
- max-width: 700px;
42
- transition: all 0.3s ease;
43
  }
44
  header { text-align: center; margin-bottom: 2.5rem; }
45
- h1 {
46
- color: var(--heading-color);
47
- font-weight: 700;
48
- margin-bottom: 0.5rem;
49
- }
50
  p.subtitle { color: var(--secondary-color); }
51
 
52
- .form-step {
53
- margin-bottom: 1.5rem;
54
- padding: 1.5rem;
55
- border: 1px solid var(--border-color);
56
- border-radius: 12px;
57
- }
58
- .form-step legend {
59
- font-size: 1.1rem;
60
- font-weight: 600;
61
- color: var(--primary-color);
62
- padding: 0 0.5rem;
63
- margin-left: 0.5rem;
64
  }
 
65
 
66
- .file-upload-label {
67
- display: block;
68
- border: 2px dashed var(--border-color);
69
- padding: 2rem;
70
- border-radius: 8px;
71
- text-align: center;
72
- cursor: pointer;
73
- transition: background-color 0.2s, border-color 0.2s;
74
- }
75
- .file-upload-label:hover {
76
- background-color: #f1f3f5;
77
- border-color: var(--primary-color);
78
- }
79
- input[type="file"] { display: none; }
80
- #file-name {
81
- margin-top: 1rem;
82
- font-style: italic;
83
- color: var(--secondary-color);
84
- }
85
 
86
- .radio-group, .checkbox-group {
87
- display: flex;
88
- gap: 1.5rem;
89
- justify-content: center;
90
- padding-top: 0.5rem;
91
- }
92
- .radio-group label, .checkbox-group label {
93
- display: inline-flex;
94
- align-items: center;
95
- cursor: pointer;
96
- }
97
 
98
  .submit-btn {
99
- width: 100%;
100
- background-image: linear-gradient(45deg, #0d6efd, #0dcaf0);
101
  color: white; border: none; padding: 1rem; border-radius: 12px;
102
- font-size: 1.2rem; font-weight: 600; cursor: pointer;
103
- transition: all 0.3s ease;
104
- box-shadow: 0 4px 15px rgba(13, 110, 253, 0.3);
105
- }
106
- .submit-btn:hover {
107
- transform: translateY(-3px);
108
- box-shadow: 0 7px 20px rgba(13, 110, 253, 0.4);
109
  }
 
110
 
111
- .result-section { margin-top: 2.5rem; border-top: 2px solid var(--border-color); padding-top: 2.5rem; }
112
- h2 { color: var(--heading-color); border-bottom: 3px solid var(--primary-color); padding-bottom: 0.5rem; display: inline-block; margin-bottom: 1.5rem; }
113
  video { width: 100%; border-radius: 12px; box-shadow: var(--shadow); }
114
- .script-box {
115
- background-color: #212529; color: #f8f9fa; border: 1px solid #343a40; padding: 1.5rem;
116
- border-radius: 8px; white-space: pre-wrap; word-wrap: break-word; font-family: "SF Mono", "Fira Code", monospace;
117
- line-height: 1.7; margin-top: 1rem; max-height: 250px; overflow-y: auto;
118
- }
119
-
120
- .flash-message {
121
- padding: 1rem; margin-bottom: 1.5rem; border-radius: 8px;
122
- background-color: #f8d7da; color: #721c24; border: 1px solid #f5c6cb;
123
- text-align: center; font-weight: 600;
124
- }
125
-
126
- #loader { text-align: center; display: none; padding: 2rem; }
127
  #loader p { font-size: 1.2rem; font-weight: 600; color: var(--primary-color); }
128
  </style>
129
  </head>
@@ -131,29 +70,33 @@
131
  <div class="container">
132
  <header>
133
  <h1>AI Video Narrator</h1>
134
- <p class="subtitle">Upload a video, choose a voice, and let AI create a new, expressive narration.</p>
135
  </header>
136
 
137
  {% with messages = get_flashed_messages() %}
138
- {% if messages %}
139
- <div class="flash-message">
140
- {{ messages[0] }}
141
- </div>
142
- {% endif %}
143
  {% endwith %}
144
 
145
  <form id="dubbing-form" action="/process" method="POST" enctype="multipart/form-data">
146
- <fieldset class="form-step">
147
- <legend>1. Upload Video</legend>
 
 
 
 
148
  <label for="video" class="file-upload-label">
149
  <span>Click to select a video file</span>
150
  <div id="file-name">No file chosen</div>
151
  </label>
152
- <input type="file" id="video" name="video" accept="video/mp4,video/mov,video/webm" required>
153
- </fieldset>
154
 
155
- <fieldset class="form-step">
156
- <legend>2. Configure Voice</legend>
 
 
 
 
157
  <div class="radio-group">
158
  <label><input type="radio" name="voice_choice" value="Male (Charon)" checked> Male Voice</label>
159
  <label><input type="radio" name="voice_choice" value="Female (Zephyr)"> Female Voice</label>
@@ -166,17 +109,12 @@
166
  <button type="submit" class="submit-btn">Generate Dubbed Video</button>
167
  </form>
168
 
169
- <div id="loader">
170
- <p>Processing your video... This may take a few minutes.</p>
171
- </div>
172
 
173
  {% if result_video %}
174
  <div class="result-section">
175
  <h2>Your Dubbed Video</h2>
176
- <video controls>
177
- <source src="{{ result_video }}" type="video/mp4">
178
- Your browser does not support the video tag.
179
- </video>
180
  <h2>Generated Script</h2>
181
  <div class="script-box">{{ script }}</div>
182
  </div>
@@ -184,24 +122,39 @@
184
  </div>
185
 
186
  <script>
 
 
187
  const form = document.getElementById('dubbing-form');
188
  const loader = document.getElementById('loader');
189
  const videoInput = document.getElementById('video');
 
190
  const fileNameDisplay = document.getElementById('file-name');
191
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
192
  videoInput.addEventListener('change', function() {
193
- if (this.files && this.files.length > 0) {
194
- fileNameDisplay.textContent = this.files[0].name;
195
- } else {
196
- fileNameDisplay.textContent = 'No file chosen';
197
- }
198
  });
199
 
200
  form.addEventListener('submit', function(event) {
201
- if (!videoInput.value) {
202
- // Prevent form submission if no file is selected
203
  event.preventDefault();
204
- alert('Please select a video file before submitting.');
205
  } else {
206
  form.style.display = 'none';
207
  loader.style.display = 'block';
 
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
  <title>AI Video Narrator</title>
7
  <style>
8
+ @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;700&display=swap');
9
 
10
  :root {
11
  --primary-color: #0d6efd;
 
14
  --card-background: #ffffff;
15
  --heading-color: #212529;
16
  --border-color: #dee2e6;
17
+ --shadow: 0 8px 30px rgba(0,0,0,0.08);
 
 
 
 
18
  }
19
 
20
+ *, *::before, *::after { box-sizing: border-box; }
21
  body {
22
+ font-family: 'Poppins', sans-serif; margin: 0; background-color: var(--background-color);
23
+ display: flex; justify-content: center; align-items: flex-start; padding: 2rem; min-height: 100vh;
 
 
 
 
 
 
24
  }
25
  .container {
26
+ background-color: var(--card-background); padding: 2.5rem 3rem; border-radius: 20px;
27
+ border: 1px solid var(--border-color); box-shadow: var(--shadow); width: 100%; max-width: 700px;
 
 
 
 
 
 
28
  }
29
  header { text-align: center; margin-bottom: 2.5rem; }
30
+ h1 { color: var(--heading-color); font-weight: 700; margin-bottom: 0.5rem; }
 
 
 
 
31
  p.subtitle { color: var(--secondary-color); }
32
 
33
+ .tab-container { display: flex; border-bottom: 2px solid var(--border-color); margin-bottom: 1.5rem; }
34
+ .tab {
35
+ padding: 0.75rem 1.5rem; cursor: pointer; font-weight: 600; color: var(--secondary-color);
36
+ border-bottom: 3px solid transparent; transition: all 0.2s;
 
 
 
 
 
 
 
 
37
  }
38
+ .tab.active { color: var(--primary-color); border-bottom-color: var(--primary-color); }
39
 
40
+ .form-content { display: none; }
41
+ .form-content.active { display: block; }
42
+
43
+ .form-step { margin-bottom: 1.5rem; padding: 1.5rem; border: 1px solid var(--border-color); border-radius: 12px; }
44
+ .form-step legend { font-size: 1.1rem; font-weight: 600; color: var(--primary-color); padding: 0 0.5rem; margin-left: 0.5rem; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
 
46
+ input[type="url"], .file-upload-label { width: 100%; border: 2px dashed var(--border-color); padding: 2rem; border-radius: 8px; text-align: center; cursor: pointer; transition: background-color 0.2s, border-color 0.2s; }
47
+ input[type="url"] { padding: 0.75rem; text-align: left; cursor: text; }
48
+ .file-upload-label:hover, input[type="url"]:focus { background-color: #f1f3f5; border-color: var(--primary-color); }
49
+ input[type="file"] { display: none; }
50
+ #file-name { margin-top: 1rem; font-style: italic; color: var(--secondary-color); }
 
 
 
 
 
 
51
 
52
  .submit-btn {
53
+ width: 100%; background-image: linear-gradient(45deg, #0d6efd, #0dcaf0);
 
54
  color: white; border: none; padding: 1rem; border-radius: 12px;
55
+ font-size: 1.2rem; font-weight: 600; cursor: pointer; transition: all 0.3s ease;
56
+ box-shadow: 0 4px 15px rgba(13, 110, 253, 0.3); margin-top: 1rem;
 
 
 
 
 
57
  }
58
+ .submit-btn:hover { transform: translateY(-3px); box-shadow: 0 7px 20px rgba(13, 110, 253, 0.4); }
59
 
60
+ .result-section, .flash-message, #loader { margin-top: 2.5rem; text-align: center; }
61
+ h2 { border-bottom: 3px solid var(--primary-color); padding-bottom: 0.5rem; display: inline-block; margin-bottom: 1.5rem; }
62
  video { width: 100%; border-radius: 12px; box-shadow: var(--shadow); }
63
+ .script-box { background-color: #212529; color: #f8f9fa; padding: 1.5rem; border-radius: 8px; text-align: left; white-space: pre-wrap; word-wrap: break-word; font-family: "SF Mono", monospace; line-height: 1.7; margin-top: 1rem; max-height: 250px; overflow-y: auto; }
64
+ .flash-message { padding: 1rem; border-radius: 8px; background-color: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; font-weight: 600; }
65
+ #loader { display: none; }
 
 
 
 
 
 
 
 
 
 
66
  #loader p { font-size: 1.2rem; font-weight: 600; color: var(--primary-color); }
67
  </style>
68
  </head>
 
70
  <div class="container">
71
  <header>
72
  <h1>AI Video Narrator</h1>
73
+ <p class="subtitle">Dub your video by uploading a file or pasting a YouTube link.</p>
74
  </header>
75
 
76
  {% with messages = get_flashed_messages() %}
77
+ {% if messages %}<div class="flash-message">{{ messages[0] }}</div>{% endif %}
 
 
 
 
78
  {% endwith %}
79
 
80
  <form id="dubbing-form" action="/process" method="POST" enctype="multipart/form-data">
81
+ <div class="tab-container">
82
+ <div class="tab active" data-tab="upload">Upload File</div>
83
+ <div class="tab" data-tab="youtube">From YouTube URL</div>
84
+ </div>
85
+
86
+ <div id="upload" class="form-content active">
87
  <label for="video" class="file-upload-label">
88
  <span>Click to select a video file</span>
89
  <div id="file-name">No file chosen</div>
90
  </label>
91
+ <input type="file" id="video" name="video" accept="video/mp4,video/mov,video/webm">
92
+ </div>
93
 
94
+ <div id="youtube" class="form-content">
95
+ <input type="url" name="youtube_url" placeholder="Paste YouTube video link here...">
96
+ </div>
97
+
98
+ <fieldset class="form-step" style="padding-top: 0.5rem;">
99
+ <legend>Configure Voice</legend>
100
  <div class="radio-group">
101
  <label><input type="radio" name="voice_choice" value="Male (Charon)" checked> Male Voice</label>
102
  <label><input type="radio" name="voice_choice" value="Female (Zephyr)"> Female Voice</label>
 
109
  <button type="submit" class="submit-btn">Generate Dubbed Video</button>
110
  </form>
111
 
112
+ <div id="loader"><p>Processing your video... This may take a few minutes.</p></div>
 
 
113
 
114
  {% if result_video %}
115
  <div class="result-section">
116
  <h2>Your Dubbed Video</h2>
117
+ <video controls src="{{ result_video }}"></video>
 
 
 
118
  <h2>Generated Script</h2>
119
  <div class="script-box">{{ script }}</div>
120
  </div>
 
122
  </div>
123
 
124
  <script>
125
+ const tabs = document.querySelectorAll('.tab');
126
+ const contents = document.querySelectorAll('.form-content');
127
  const form = document.getElementById('dubbing-form');
128
  const loader = document.getElementById('loader');
129
  const videoInput = document.getElementById('video');
130
+ const urlInput = document.querySelector('input[name="youtube_url"]');
131
  const fileNameDisplay = document.getElementById('file-name');
132
 
133
+ tabs.forEach(tab => {
134
+ tab.addEventListener('click', () => {
135
+ tabs.forEach(item => item.classList.remove('active'));
136
+ contents.forEach(item => item.classList.remove('active'));
137
+ tab.classList.add('active');
138
+ document.getElementById(tab.dataset.tab).classList.add('active');
139
+
140
+ // Clear the other input when switching tabs
141
+ if (tab.dataset.tab === 'upload') {
142
+ urlInput.value = '';
143
+ } else {
144
+ videoInput.value = '';
145
+ fileNameDisplay.textContent = 'No file chosen';
146
+ }
147
+ });
148
+ });
149
+
150
  videoInput.addEventListener('change', function() {
151
+ fileNameDisplay.textContent = this.files.length > 0 ? this.files[0].name : 'No file chosen';
 
 
 
 
152
  });
153
 
154
  form.addEventListener('submit', function(event) {
155
+ if (!videoInput.value && !urlInput.value) {
 
156
  event.preventDefault();
157
+ alert('Please either select a video file or enter a YouTube URL.');
158
  } else {
159
  form.style.display = 'none';
160
  loader.style.display = 'block';