Kalp97 commited on
Commit
638594e
·
verified ·
1 Parent(s): 59d7784

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +226 -74
app.py CHANGED
@@ -1,173 +1,325 @@
1
  import gradio as gr
2
  import whisper
 
3
 
4
- model = None
5
 
6
- def load_model():
7
- global model
8
- if model is None:
9
- model = whisper.load_model("base")
10
- return model
11
 
12
- def transcribe(file):
13
  if file is None:
14
- return "Please upload a video or audio file."
 
15
  try:
16
- m = load_model()
17
- result = m.transcribe(file.name, language="en", verbose=False)
18
- return result["text"].strip()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  except Exception as e:
20
- return f"Error: {str(e)}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
 
22
  custom_css = """
23
- @import url('https://fonts.googleapis.com/css2?family=DM+Serif+Display:ital@0;1&family=DM+Sans:wght@300;400;500&display=swap');
24
 
25
  * { box-sizing: border-box; }
26
 
27
  body, .gradio-container {
28
- background: #0a0a0a !important;
29
  font-family: 'DM Sans', sans-serif !important;
30
  }
31
 
32
  .gradio-container {
33
- max-width: 920px !important;
34
  margin: 0 auto !important;
35
- padding: 48px 24px !important;
36
  }
37
 
 
 
 
 
 
 
 
 
 
 
 
38
  .prose h1 {
39
  font-family: 'DM Serif Display', serif !important;
40
- font-size: 2.8rem !important;
41
  font-weight: 400 !important;
42
  color: #f0ece2 !important;
43
  letter-spacing: -0.02em !important;
44
- line-height: 1.1 !important;
45
  margin-bottom: 0 !important;
46
  }
47
 
48
  .prose p {
49
- font-family: 'DM Sans', sans-serif !important;
50
- color: #6b6860 !important;
51
- font-size: 0.95rem !important;
52
  font-weight: 300 !important;
53
- margin-top: 10px !important;
 
54
  }
55
 
56
- .contain, .gap {
57
- background: transparent !important;
58
- border: none !important;
59
- gap: 20px !important;
60
- }
61
 
62
  .block {
63
- background: #111111 !important;
64
- border: 1px solid #1e1e1e !important;
65
- border-radius: 16px !important;
 
66
  }
67
 
68
- .block label span {
 
 
 
69
  font-family: 'DM Sans', sans-serif !important;
70
- font-size: 0.75rem !important;
71
  font-weight: 500 !important;
72
- color: #6b6860 !important;
73
  text-transform: uppercase !important;
74
- letter-spacing: 0.1em !important;
 
 
 
 
 
 
 
 
 
 
75
  }
76
 
 
77
  textarea {
78
  background: transparent !important;
79
- color: #f0ece2 !important;
80
  font-family: 'DM Sans', sans-serif !important;
81
- font-size: 0.95rem !important;
82
- line-height: 1.8 !important;
83
  font-weight: 300 !important;
84
  border: none !important;
 
85
  }
86
 
87
- .file-preview, .upload-container {
88
- background: transparent !important;
89
- border: none !important;
90
- color: #555 !important;
91
- }
92
 
 
 
 
 
93
  button.primary {
94
  background: #c9a96e !important;
95
  border: none !important;
96
- border-radius: 12px !important;
97
- color: #0a0a0a !important;
98
  font-family: 'DM Sans', sans-serif !important;
99
- font-size: 0.8rem !important;
100
  font-weight: 500 !important;
101
- letter-spacing: 0.1em !important;
102
  text-transform: uppercase !important;
103
  padding: 14px 28px !important;
104
  transition: all 0.2s ease !important;
 
105
  }
106
 
107
  button.primary:hover {
108
  background: #d4b87e !important;
109
  transform: translateY(-1px) !important;
110
- box-shadow: 0 4px 20px rgba(201,169,110,0.25) !important;
111
  }
112
 
 
 
 
113
  button.secondary {
114
  background: transparent !important;
115
- border: 1px solid #222 !important;
116
- border-radius: 12px !important;
117
- color: #555 !important;
118
  font-family: 'DM Sans', sans-serif !important;
119
- font-size: 0.8rem !important;
120
  font-weight: 500 !important;
121
- letter-spacing: 0.1em !important;
122
  text-transform: uppercase !important;
123
  transition: all 0.2s ease !important;
124
  }
125
 
126
  button.secondary:hover {
127
- border-color: #444 !important;
128
- color: #f0ece2 !important;
129
  }
130
 
131
- footer { display: none !important; }
 
 
 
 
132
 
133
- textarea::-webkit-scrollbar { width: 4px; }
134
- textarea::-webkit-scrollbar-track { background: transparent; }
135
- textarea::-webkit-scrollbar-thumb { background: #2a2a2a; border-radius: 4px; }
 
 
 
 
 
 
 
 
 
 
 
136
 
137
- .gradio-container::before {
138
- content: '';
139
- display: block;
140
- width: 36px;
141
- height: 2px;
142
- background: #c9a96e;
143
- margin-bottom: 28px;
144
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
145
  """
146
 
 
 
 
 
 
 
147
  with gr.Blocks(css=custom_css, title="KalpTranscript") as demo:
 
148
  gr.Markdown("""
149
  # KalpTranscript
150
  Turn any video or audio into clean, readable text — powered by OpenAI Whisper.
151
  """)
152
 
153
  with gr.Row():
154
- with gr.Column():
 
155
  file_input = gr.File(
156
  label="Drop your file here",
157
  file_types=["video", "audio"]
158
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
159
  with gr.Row():
160
  clear_btn = gr.ClearButton(value="Clear")
161
  submit_btn = gr.Button("Transcribe →", variant="primary")
162
 
163
- with gr.Column():
164
- output = gr.Textbox(
165
- label="Transcript",
166
- lines=14,
167
- placeholder="Your transcript will appear here..."
168
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
169
 
170
- submit_btn.click(fn=transcribe, inputs=file_input, outputs=output)
 
 
 
 
171
 
172
  if __name__ == "__main__":
173
- demo.launch()
 
1
  import gradio as gr
2
  import whisper
3
+ import os
4
 
5
+ models = {}
6
 
7
+ def load_model(model_name):
8
+ global models
9
+ if model_name not in models:
10
+ models[model_name] = whisper.load_model(model_name)
11
+ return models[model_name]
12
 
13
+ def transcribe(file, model_name, language, show_timestamps, task):
14
  if file is None:
15
+ return "Please upload a video or audio file.", ""
16
+
17
  try:
18
+ m = load_model(model_name)
19
+
20
+ lang = None if language == "Auto Detect" else language.lower()
21
+
22
+ result = m.transcribe(
23
+ file.name,
24
+ language=lang,
25
+ verbose=False,
26
+ task="translate" if task == "Translate to English" else "transcribe"
27
+ )
28
+
29
+ # Full plain transcript
30
+ plain = result["text"].strip()
31
+
32
+ # Timestamped transcript
33
+ if show_timestamps:
34
+ lines = []
35
+ for seg in result["segments"]:
36
+ start = format_time(seg["start"])
37
+ end = format_time(seg["end"])
38
+ lines.append(f"[{start} → {end}] {seg['text'].strip()}")
39
+ timestamped = "\n".join(lines)
40
+ else:
41
+ timestamped = plain
42
+
43
+ return timestamped, plain
44
+
45
  except Exception as e:
46
+ return f"Error: {str(e)}", ""
47
+
48
+ def format_time(seconds):
49
+ m = int(seconds // 60)
50
+ s = int(seconds % 60)
51
+ ms = int((seconds % 1) * 10)
52
+ return f"{m:02d}:{s:02d}.{ms}"
53
+
54
+ def save_transcript(text):
55
+ if not text:
56
+ return None
57
+ path = "/tmp/transcript.txt"
58
+ with open(path, "w", encoding="utf-8") as f:
59
+ f.write(text)
60
+ return path
61
 
62
  custom_css = """
63
+ @import url('https://fonts.googleapis.com/css2?family=DM+Serif+Display:ital@0;1&family=DM+Sans:opsz,wght@9..40,300;9..40,400;9..40,500&display=swap');
64
 
65
  * { box-sizing: border-box; }
66
 
67
  body, .gradio-container {
68
+ background: #080808 !important;
69
  font-family: 'DM Sans', sans-serif !important;
70
  }
71
 
72
  .gradio-container {
73
+ max-width: 1000px !important;
74
  margin: 0 auto !important;
75
+ padding: 48px 28px 80px !important;
76
  }
77
 
78
+ /* Gold bar */
79
+ .gradio-container::before {
80
+ content: '';
81
+ display: block;
82
+ width: 36px;
83
+ height: 2px;
84
+ background: #c9a96e;
85
+ margin-bottom: 32px;
86
+ }
87
+
88
+ /* Title */
89
  .prose h1 {
90
  font-family: 'DM Serif Display', serif !important;
91
+ font-size: 3rem !important;
92
  font-weight: 400 !important;
93
  color: #f0ece2 !important;
94
  letter-spacing: -0.02em !important;
95
+ line-height: 1.05 !important;
96
  margin-bottom: 0 !important;
97
  }
98
 
99
  .prose p {
100
+ color: #555 !important;
101
+ font-size: 0.9rem !important;
 
102
  font-weight: 300 !important;
103
+ margin-top: 8px !important;
104
+ letter-spacing: 0.01em !important;
105
  }
106
 
107
+ /* Panels */
108
+ .contain, .gap { background: transparent !important; border: none !important; }
 
 
 
109
 
110
  .block {
111
+ background: #0f0f0f !important;
112
+ border: 1px solid #1c1c1c !important;
113
+ border-radius: 14px !important;
114
+ transition: border-color 0.2s !important;
115
  }
116
 
117
+ .block:hover { border-color: #2a2a2a !important; }
118
+
119
+ /* Labels */
120
+ .block label > span, label > span {
121
  font-family: 'DM Sans', sans-serif !important;
122
+ font-size: 0.72rem !important;
123
  font-weight: 500 !important;
124
+ color: #4a4a4a !important;
125
  text-transform: uppercase !important;
126
+ letter-spacing: 0.12em !important;
127
+ }
128
+
129
+ /* Dropdowns & selects */
130
+ select, .wrap-inner, input[type="text"] {
131
+ background: #0f0f0f !important;
132
+ color: #c8c4bc !important;
133
+ border: 1px solid #1c1c1c !important;
134
+ border-radius: 10px !important;
135
+ font-family: 'DM Sans', sans-serif !important;
136
+ font-size: 0.88rem !important;
137
  }
138
 
139
+ /* Textarea */
140
  textarea {
141
  background: transparent !important;
142
+ color: #d4d0c8 !important;
143
  font-family: 'DM Sans', sans-serif !important;
144
+ font-size: 0.92rem !important;
145
+ line-height: 1.85 !important;
146
  font-weight: 300 !important;
147
  border: none !important;
148
+ letter-spacing: 0.01em !important;
149
  }
150
 
151
+ textarea::placeholder { color: #2e2e2e !important; }
 
 
 
 
152
 
153
+ /* Checkbox */
154
+ input[type="checkbox"] { accent-color: #c9a96e !important; }
155
+
156
+ /* Primary button */
157
  button.primary {
158
  background: #c9a96e !important;
159
  border: none !important;
160
+ border-radius: 11px !important;
161
+ color: #080808 !important;
162
  font-family: 'DM Sans', sans-serif !important;
163
+ font-size: 0.78rem !important;
164
  font-weight: 500 !important;
165
+ letter-spacing: 0.12em !important;
166
  text-transform: uppercase !important;
167
  padding: 14px 28px !important;
168
  transition: all 0.2s ease !important;
169
+ box-shadow: 0 2px 12px rgba(201,169,110,0.15) !important;
170
  }
171
 
172
  button.primary:hover {
173
  background: #d4b87e !important;
174
  transform: translateY(-1px) !important;
175
+ box-shadow: 0 6px 24px rgba(201,169,110,0.3) !important;
176
  }
177
 
178
+ button.primary:active { transform: translateY(0) !important; }
179
+
180
+ /* Secondary button */
181
  button.secondary {
182
  background: transparent !important;
183
+ border: 1px solid #1e1e1e !important;
184
+ border-radius: 11px !important;
185
+ color: #4a4a4a !important;
186
  font-family: 'DM Sans', sans-serif !important;
187
+ font-size: 0.78rem !important;
188
  font-weight: 500 !important;
189
+ letter-spacing: 0.12em !important;
190
  text-transform: uppercase !important;
191
  transition: all 0.2s ease !important;
192
  }
193
 
194
  button.secondary:hover {
195
+ border-color: #3a3a3a !important;
196
+ color: #c8c4bc !important;
197
  }
198
 
199
+ /* Download button area */
200
+ .file-preview {
201
+ background: transparent !important;
202
+ border: none !important;
203
+ }
204
 
205
+ /* Tabs */
206
+ .tab-nav button {
207
+ font-family: 'DM Sans', sans-serif !important;
208
+ font-size: 0.78rem !important;
209
+ font-weight: 500 !important;
210
+ letter-spacing: 0.1em !important;
211
+ text-transform: uppercase !important;
212
+ color: #4a4a4a !important;
213
+ background: transparent !important;
214
+ border: none !important;
215
+ border-bottom: 2px solid transparent !important;
216
+ padding: 10px 16px !important;
217
+ transition: all 0.2s !important;
218
+ }
219
 
220
+ .tab-nav button.selected {
221
+ color: #c9a96e !important;
222
+ border-bottom-color: #c9a96e !important;
 
 
 
 
223
  }
224
+
225
+ /* Divider */
226
+ .divider { border-color: #1c1c1c !important; }
227
+
228
+ /* Progress */
229
+ .progress-bar { background: #c9a96e !important; }
230
+ .progress-bar-wrap { background: #1c1c1c !important; }
231
+
232
+ /* Scrollbar */
233
+ ::-webkit-scrollbar { width: 3px; }
234
+ ::-webkit-scrollbar-track { background: transparent; }
235
+ ::-webkit-scrollbar-thumb { background: #2a2a2a; border-radius: 4px; }
236
+
237
+ footer { display: none !important; }
238
+
239
+ /* Settings row */
240
+ .settings-row { gap: 12px !important; }
241
  """
242
 
243
+ LANGUAGES = [
244
+ "Auto Detect", "English", "Hindi", "Spanish", "French",
245
+ "German", "Italian", "Portuguese", "Chinese", "Japanese",
246
+ "Korean", "Arabic", "Russian", "Dutch", "Turkish"
247
+ ]
248
+
249
  with gr.Blocks(css=custom_css, title="KalpTranscript") as demo:
250
+
251
  gr.Markdown("""
252
  # KalpTranscript
253
  Turn any video or audio into clean, readable text — powered by OpenAI Whisper.
254
  """)
255
 
256
  with gr.Row():
257
+ # Left column - controls
258
+ with gr.Column(scale=1):
259
  file_input = gr.File(
260
  label="Drop your file here",
261
  file_types=["video", "audio"]
262
  )
263
+
264
+ with gr.Row(elem_classes=["settings-row"]):
265
+ model_choice = gr.Dropdown(
266
+ choices=["tiny", "base", "small", "medium"],
267
+ value="small",
268
+ label="Model",
269
+ info="small = fast & accurate, medium = best quality"
270
+ )
271
+ language = gr.Dropdown(
272
+ choices=LANGUAGES,
273
+ value="Auto Detect",
274
+ label="Language"
275
+ )
276
+
277
+ with gr.Row():
278
+ task = gr.Radio(
279
+ choices=["Transcribe", "Translate to English"],
280
+ value="Transcribe",
281
+ label="Task"
282
+ )
283
+
284
+ timestamps = gr.Checkbox(
285
+ label="Show timestamps",
286
+ value=False
287
+ )
288
+
289
  with gr.Row():
290
  clear_btn = gr.ClearButton(value="Clear")
291
  submit_btn = gr.Button("Transcribe →", variant="primary")
292
 
293
+ # Right column - output
294
+ with gr.Column(scale=1):
295
+ with gr.Tabs():
296
+ with gr.Tab("Transcript"):
297
+ output = gr.Textbox(
298
+ label="",
299
+ lines=16,
300
+ placeholder="Your transcript will appear here...",
301
+ show_copy_button=False
302
+ )
303
+ with gr.Tab("Download"):
304
+ plain_output = gr.Textbox(
305
+ label="Plain text (for download)",
306
+ lines=10,
307
+ visible=False
308
+ )
309
+ download_btn = gr.Button("Save as .txt", variant="secondary")
310
+ download_file = gr.File(label="Download", visible=True)
311
+
312
+ submit_btn.click(
313
+ fn=transcribe,
314
+ inputs=[file_input, model_choice, language, timestamps, task],
315
+ outputs=[output, plain_output]
316
+ )
317
 
318
+ download_btn.click(
319
+ fn=save_transcript,
320
+ inputs=plain_output,
321
+ outputs=download_file
322
+ )
323
 
324
  if __name__ == "__main__":
325
+ demo.launch()