lvvignesh2122 commited on
Commit
ef2a1d2
Β·
verified Β·
1 Parent(s): 3bc5fd7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +93 -52
app.py CHANGED
@@ -3,18 +3,18 @@ import tempfile
3
  from pathlib import Path
4
  import gradio as gr
5
  import ffmpeg
6
- from faster_whisper import WhisperModel
7
 
8
  # -------- Helper functions --------
9
  def _format_timestamp(seconds: float) -> str:
10
  ms = int(round(seconds * 1000))
11
  hours = ms // 3600000
12
- ms_rem = ms % 3600000
13
- minutes = ms_rem // 60000
14
- ms_rem = ms_rem % 60000
15
- secs = ms_rem // 1000
16
- millis = ms_rem % 1000
17
- return f"{hours:02d}:{minutes:02d}:{secs:02d},{millis:03d}"
18
 
19
 
20
  def segments_to_srt(segments: list) -> str:
@@ -22,71 +22,98 @@ def segments_to_srt(segments: list) -> str:
22
  for i, seg in enumerate(segments, start=1):
23
  start_ts = _format_timestamp(seg["start"])
24
  end_ts = _format_timestamp(seg["end"])
25
- text = seg["text"].replace("\n", " ").strip()
26
- if not text:
27
- continue
28
- block = f"{i}\n{start_ts} --> {end_ts}\n{text}\n"
29
- lines.append(block)
30
  return "\n".join(lines)
31
 
32
 
33
  # -------- Config --------
34
- MODEL_NAME = "Systran/faster-whisper-small" # good for HF CPU
35
- DEVICE = "cpu"
36
  OUTPUT_DIR = Path("outputs/subtitles")
37
  OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
38
 
39
- print(f"Loading model {MODEL_NAME} on {DEVICE} ...")
40
- model = WhisperModel(MODEL_NAME, device=DEVICE)
41
- print("Model loaded.")
42
 
43
 
44
  # -------- Core functions --------
45
  def extract_audio(input_path: str, out_path: str):
46
- """Extracts mono 16 kHz WAV using ffmpeg"""
47
- try:
48
- (
49
- ffmpeg
50
- .input(input_path)
51
- .output(out_path, format="wav", acodec="pcm_s16le", ac=1, ar="16000")
52
- .overwrite_output()
53
- .run(quiet=True)
54
- )
55
- except ffmpeg.Error as e:
56
- stderr = getattr(e, "stderr", None)
57
- msg = stderr.decode() if stderr else str(e)
58
- raise RuntimeError(f"ffmpeg error: {msg}")
59
-
60
-
61
- def transcribe_file_to_srt(file_obj, language: str = "en"):
62
- """Transcribe uploaded file to SRT; compatible with HF Spaces"""
63
- tmp_dir = Path(tempfile.mkdtemp(prefix="subgen_"))
64
 
65
- # Handle file object
 
 
66
  input_path = tmp_dir / Path(file_obj.name).name
67
  with open(input_path, "wb") as f:
68
  f.write(file_obj.read())
69
 
70
- # Extract audio and transcribe
71
  audio_path = tmp_dir / "audio.wav"
72
  extract_audio(str(input_path), str(audio_path))
73
- segments, _ = model.transcribe(str(audio_path), language=language)
74
- segs = [{"start": s.start, "end": s.end, "text": s.text} for s in segments]
75
- srt_text = segments_to_srt(segs)
76
 
77
- # Save .srt file
 
 
 
 
 
 
 
 
 
78
  output_path = OUTPUT_DIR / f"{Path(file_obj.name).stem}.srt"
79
- with open(output_path, "w", encoding="utf-8") as f:
80
- f.write(srt_text)
81
  return str(output_path), "βœ… Subtitles generated successfully!"
82
 
83
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
  # -------- Gradio UI --------
85
  with gr.Blocks(title="AI Subtitle Generator") as demo:
 
 
 
86
  gr.HTML("<h1 style='text-align:center;'>🎬 AI Subtitle Generator</h1>")
87
- gr.HTML(
88
- "<p style='text-align:center;'>Upload a video or audio file to generate English <b>.srt</b> subtitles.</p>"
89
- )
90
 
91
  with gr.Row():
92
  input_file = gr.File(label="Upload video/audio file")
@@ -94,16 +121,30 @@ with gr.Blocks(title="AI Subtitle Generator") as demo:
94
 
95
  status_box = gr.Textbox(label="Status", interactive=False)
96
 
97
- def on_click(file):
 
 
 
 
 
 
 
 
98
  srt_path, msg = transcribe_file_to_srt(file)
99
  return srt_path, msg
100
 
101
- generate_btn = gr.Button("Generate Subtitles")
102
- generate_btn.click(on_click, inputs=[input_file], outputs=[output_file, status_box])
103
 
104
- gr.HTML(
105
- "<p style='text-align:center;font-size:14px;opacity:0.7;'>Powered by Faster-Whisper + Gradio</p>"
106
- )
 
 
 
 
 
 
107
 
108
  if __name__ == "__main__":
109
  demo.launch()
 
3
  from pathlib import Path
4
  import gradio as gr
5
  import ffmpeg
6
+ import whisper
7
 
8
  # -------- Helper functions --------
9
  def _format_timestamp(seconds: float) -> str:
10
  ms = int(round(seconds * 1000))
11
  hours = ms // 3600000
12
+ ms %= 3600000
13
+ minutes = ms // 60000
14
+ ms %= 60000
15
+ seconds = ms // 1000
16
+ millis = ms % 1000
17
+ return f"{hours:02d}:{minutes:02d}:{seconds:02d},{millis:03d}"
18
 
19
 
20
  def segments_to_srt(segments: list) -> str:
 
22
  for i, seg in enumerate(segments, start=1):
23
  start_ts = _format_timestamp(seg["start"])
24
  end_ts = _format_timestamp(seg["end"])
25
+ text = seg["text"].strip().replace("\n", " ")
26
+ if text:
27
+ lines.append(f"{i}\n{start_ts} --> {end_ts}\n{text}\n")
 
 
28
  return "\n".join(lines)
29
 
30
 
31
  # -------- Config --------
32
+ MODEL_NAME = "base"
 
33
  OUTPUT_DIR = Path("outputs/subtitles")
34
  OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
35
 
36
+ print(f"Loading Whisper model '{MODEL_NAME}'...")
37
+ model = whisper.load_model(MODEL_NAME)
38
+ print("Model loaded successfully!")
39
 
40
 
41
  # -------- Core functions --------
42
  def extract_audio(input_path: str, out_path: str):
43
+ """Extract mono 16 kHz WAV using ffmpeg"""
44
+ (
45
+ ffmpeg
46
+ .input(input_path)
47
+ .output(out_path, format="wav", acodec="pcm_s16le", ac=1, ar="16000")
48
+ .overwrite_output()
49
+ .run(quiet=True)
50
+ )
 
 
 
 
 
 
 
 
 
 
51
 
52
+
53
+ def transcribe_file_to_srt(file_obj, language="en"):
54
+ tmp_dir = Path(tempfile.mkdtemp(prefix="subgen_"))
55
  input_path = tmp_dir / Path(file_obj.name).name
56
  with open(input_path, "wb") as f:
57
  f.write(file_obj.read())
58
 
 
59
  audio_path = tmp_dir / "audio.wav"
60
  extract_audio(str(input_path), str(audio_path))
 
 
 
61
 
62
+ result = model.transcribe(str(audio_path), language=language)
63
+ segments = []
64
+ for i, seg in enumerate(result["segments"]):
65
+ segments.append({
66
+ "start": seg["start"],
67
+ "end": seg["end"],
68
+ "text": seg["text"]
69
+ })
70
+
71
+ srt_text = segments_to_srt(segments)
72
  output_path = OUTPUT_DIR / f"{Path(file_obj.name).stem}.srt"
73
+ output_path.write_text(srt_text, encoding="utf-8")
74
+
75
  return str(output_path), "βœ… Subtitles generated successfully!"
76
 
77
 
78
+ # -------- UI Styling --------
79
+ def build_style(theme="light"):
80
+ if theme == "dark":
81
+ bg = "#0f2027"
82
+ color = "#ffffff"
83
+ button = "#00adb5"
84
+ else:
85
+ bg = "#f0f2f5"
86
+ color = "#000000"
87
+ button = "#0077ff"
88
+
89
+ return f"""
90
+ <style>
91
+ body {{
92
+ background: {bg};
93
+ color: {color};
94
+ font-family: 'Poppins', sans-serif;
95
+ transition: background 0.5s, color 0.5s;
96
+ }}
97
+ .gr-button {{
98
+ background-color: {button} !important;
99
+ color: white !important;
100
+ font-weight: bold;
101
+ border-radius: 10px !important;
102
+ }}
103
+ .gr-button:hover {{
104
+ filter: brightness(1.2);
105
+ }}
106
+ </style>
107
+ """
108
+
109
+
110
  # -------- Gradio UI --------
111
  with gr.Blocks(title="AI Subtitle Generator") as demo:
112
+ theme_state = gr.State("light")
113
+
114
+ style_html = gr.HTML(build_style("light"))
115
  gr.HTML("<h1 style='text-align:center;'>🎬 AI Subtitle Generator</h1>")
116
+ gr.HTML("<p style='text-align:center;'>Upload a video or audio file to generate English <b>.srt</b> subtitles.</p>")
 
 
117
 
118
  with gr.Row():
119
  input_file = gr.File(label="Upload video/audio file")
 
121
 
122
  status_box = gr.Textbox(label="Status", interactive=False)
123
 
124
+ with gr.Row():
125
+ generate_btn = gr.Button("πŸš€ Generate Subtitles")
126
+ clear_btn = gr.Button("🧹 Clear Chat")
127
+ theme_btn = gr.Button("πŸŒ— Toggle Theme")
128
+
129
+ # Button logic
130
+ def on_generate(file):
131
+ if not file:
132
+ return None, "⚠️ Please upload a file first!"
133
  srt_path, msg = transcribe_file_to_srt(file)
134
  return srt_path, msg
135
 
136
+ def on_clear():
137
+ return None, None, ""
138
 
139
+ def on_theme(current):
140
+ new_theme = "dark" if current == "light" else "light"
141
+ return new_theme, gr.update(value=build_style(new_theme))
142
+
143
+ generate_btn.click(on_generate, inputs=[input_file], outputs=[output_file, status_box])
144
+ clear_btn.click(on_clear, outputs=[input_file, output_file, status_box])
145
+ theme_btn.click(on_theme, inputs=[theme_state], outputs=[theme_state, style_html])
146
+
147
+ gr.HTML("<p style='text-align:center;font-size:14px;opacity:0.6;'>✨ Built with OpenAI Whisper + Gradio</p>")
148
 
149
  if __name__ == "__main__":
150
  demo.launch()