Wahso commited on
Commit
23c65d1
·
verified ·
1 Parent(s): e0f3ea8

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +111 -293
app.py CHANGED
@@ -1,226 +1,117 @@
1
  import gradio as gr
2
  import cv2
3
  import numpy as np
4
- import tempfile
5
- import os
6
  import json
7
- from PIL import Image
8
- import time
9
- import math
10
 
11
- # ============================================================================
12
- # 📋 OCR FUNCTION (Video Hardsub Extractor)
13
- # ============================================================================
14
-
15
- def extract_subtitles(video_file, language, start_time, end_time,
16
- box_x, box_y, box_w, box_h, aspect_lock):
17
  """
18
- Video ထဲက hardcoded subtitles တွေကို ထုတ်ပေးမယ့် function
19
  """
20
- # Video ဖိုင်ကိုဖွင့်မယ်
21
- cap = cv2.VideoCapture(video_file)
22
 
23
- # Video info
 
24
  fps = cap.get(cv2.CAP_PROP_FPS)
25
- total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
26
  width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
27
  height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
28
 
29
- # Start/End time ကို frame number အဖြစ်ပြောင်းမယ်
30
- start_frame = max(0, int(start_time * fps))
31
- end_frame = min(total_frames, int(end_time * fps))
 
 
 
 
32
 
33
- # စာတန်းတွေသိမ်းမယ့် list
34
  subtitles = []
35
  last_text = ""
36
- current_start = start_time
37
- frame_count = 0
38
- total_frames_to_process = end_frame - start_frame
39
-
40
- # Progress updates
41
- progress = []
42
-
43
- # Frame အလိုက်ဖတ်မယ် (1 FPS sampling)
44
- sample_interval = int(fps) # 1 frame per second
45
-
46
- cap.set(cv2.CAP_PROP_POS_FRAMES, start_frame)
47
 
 
48
  for frame_num in range(start_frame, end_frame, sample_interval):
49
  ret, frame = cap.read()
50
  if not ret:
51
  break
52
-
53
  frame_count += 1
54
  current_time = frame_num / fps
55
 
56
- # Progress calculation
57
- progress_percent = (frame_count / (total_frames_to_process / sample_interval)) * 100
58
-
59
- # ရွေးထားတဲ့နေရာကိုဖြတ်မယ်
60
- x1 = int((box_x / 100) * width)
61
- y1 = int((box_y / 100) * height)
62
- x2 = int(((box_x + box_w) / 100) * width)
63
- y2 = int(((box_y + box_h) / 100) * height)
64
-
65
- # Ensure coordinates are within frame
66
- x1 = max(0, min(x1, width-1))
67
- y1 = max(0, min(y1, height-1))
68
- x2 = max(x1+1, min(x2, width))
69
- y2 = max(y1+1, min(y2, height))
70
-
71
- crop = frame[y1:y2, x1:x2]
72
 
73
- # OCR Simulation - ဒီနေရာမှာ တကယ့် OCR engine ထည့်လို့ရတယ်
74
- text = simulate_ocr(crop, language, current_time)
 
75
 
76
- # စာသားတူရင် merge လုပ်မယ်
77
  if text and text != last_text:
78
  if last_text:
79
  subtitles.append({
80
- 'start': current_start,
81
- 'end': current_time,
82
- 'text': last_text,
83
- 'status': 'exited'
84
  })
85
  current_start = current_time
86
  last_text = text
87
-
88
- # Add entered status
89
- subtitles.append({
90
- 'start': current_time,
91
- 'end': current_time,
92
- 'text': text,
93
- 'status': 'entered'
94
- })
95
 
96
- # နောက်ဆုံးစာတန်းကိုထည့်မယ်
97
  if last_text:
98
  subtitles.append({
99
- 'start': current_start,
100
- 'end': end_time,
101
- 'text': last_text,
102
- 'status': 'exited'
103
  })
104
 
105
  cap.release()
106
 
107
- # SRT format ပြောင်းမယ်
108
- srt_content = generate_srt(subtitles)
 
 
109
 
110
- # JSON format ပြောင်းမယ်
111
- json_content = generate_json(subtitles)
112
 
113
- # TXT format ပြောင်းမယ်
114
- txt_content = generate_txt(subtitles)
 
 
115
 
116
- # ဖိုင်တွေသိမ်းမယ်
117
- srt_path = "extracted_subtitles.srt"
118
- json_path = "extracted_subtitles.json"
119
- txt_path = "extracted_subtitles.txt"
120
 
121
  with open(srt_path, "w", encoding="utf-8") as f:
122
  f.write(srt_content)
123
-
124
  with open(json_path, "w", encoding="utf-8") as f:
125
  f.write(json_content)
126
-
127
  with open(txt_path, "w", encoding="utf-8") as f:
128
  f.write(txt_content)
129
 
130
- # စာတန်းစာရင်းကို Dataframe အတွက်ပြင်ဆင်မယ်
131
- subtitle_list = []
132
- for s in subtitles:
133
- if s['status'] != 'entered': # Only show actual subtitle lines
134
- subtitle_list.append([
135
- format_time(s['start']),
136
- format_time(s['end']),
137
- s['text'][:50] + "..." if len(s['text']) > 50 else s['text']
138
- ])
139
 
140
- return srt_path, json_path, txt_path, subtitle_list, f"Processed {frame_count} frames"
141
-
142
- def simulate_ocr(image, language, current_time):
143
- """
144
- OCR Simulation - တကယ့် OCR အတွက် placeholder
145
- """
146
- # Sample texts for demonstration
147
- samples = [
148
- "Hello and welcome",
149
- "နမူနာစာသား",
150
- "ตัวอย่างข้อความ",
151
- "サンプルテキスト",
152
- "샘플 텍스트",
153
- "示例文本",
154
- "ข้อความตัวอย่าง"
155
- ]
156
-
157
- # Return sample text based on time
158
- idx = int(current_time) % len(samples)
159
- return samples[idx] if idx < len(samples) else ""
160
-
161
- def generate_srt(subtitles):
162
- """SRT format ပြောင်းမယ်"""
163
- srt_content = ""
164
- counter = 1
165
-
166
- for i, sub in enumerate(subtitles):
167
- if sub['status'] != 'entered':
168
- start = format_time(sub['start'])
169
- end = format_time(sub['end'])
170
- srt_content += f"{counter}\n{start} --> {end}\n{sub['text']}\n\n"
171
- counter += 1
172
-
173
- return srt_content
174
-
175
- def generate_json(subtitles):
176
- """JSON format ပြောင်းမယ်"""
177
- json_list = []
178
- for sub in subtitles:
179
- if sub['status'] != 'entered':
180
- json_list.append({
181
- 'start': sub['start'],
182
- 'start_formatted': format_time(sub['start']),
183
- 'end': sub['end'],
184
- 'end_formatted': format_time(sub['end']),
185
- 'text': sub['text']
186
- })
187
- return json.dumps(json_list, indent=2, ensure_ascii=False)
188
-
189
- def generate_txt(subtitles):
190
- """TXT format ပြောင်းမယ်"""
191
- txt_content = ""
192
- for sub in subtitles:
193
- if sub['status'] != 'entered':
194
- txt_content += f"[{format_time(sub['start'])} --> {format_time(sub['end'])}] {sub['text']}\n"
195
- return txt_content
196
 
197
  def format_time(seconds):
198
- """အချိန်ကို SRT format (HH:MM:SS,mmm) ပြောင်းမယ်"""
199
  h = int(seconds // 3600)
200
  m = int((seconds % 3600) // 60)
201
  s = int(seconds % 60)
202
  ms = int((seconds - int(seconds)) * 1000)
203
  return f"{h:02d}:{m:02d}:{s:02d},{ms:03d}"
204
 
205
- def set_start_from_video(current_time):
206
- return current_time
207
-
208
- def set_end_from_video(current_time):
209
- return current_time
210
-
211
- def reset_adjustments():
212
- return 10, 80, 80, 15
213
-
214
- def toggle_aspect_lock(current_lock):
215
- return not current_lock
216
-
217
  def update_duration(start, end):
218
  return max(0, end - start)
219
 
220
  def set_full_video(duration):
221
  return 0, duration
222
 
223
- def update_video_info(video):
224
  if video:
225
  cap = cv2.VideoCapture(video)
226
  fps = cap.get(cv2.CAP_PROP_FPS)
@@ -230,148 +121,75 @@ def update_video_info(video):
230
  return duration, duration, 0
231
  return 0, 0, 0
232
 
233
- # ============================================================================
234
- # 📋 GRADIO INTERFACE
235
- # ============================================================================
236
-
237
- custom_css = """
238
- .highlight-subtitle {
239
- background-color: #fff3c9 !important;
240
- border-left: 4px solid #f5b342 !important;
241
- font-weight: bold !important;
242
- box-shadow: 0 0 15px #f5b342 !important;
243
- transition: all 0.3s ease;
244
- }
245
- .entered-subtitle {
246
- background-color: #e6f7ff !important;
247
- border-left: 4px solid #1890ff !important;
248
- }
249
- .exited-subtitle {
250
- opacity: 0.7;
251
- }
252
- """
253
-
254
- with gr.Blocks(theme=gr.themes.Soft(), title="Video Hardsub OCR", css=custom_css) as demo:
255
- gr.Markdown("""
256
- # 🎬 Video Hardsub OCR Extractor
257
- ### Video ထဲက hardcoded စာတန်းတွေကို ထုတ်ယူပါ။
258
- """)
259
-
260
- current_time_state = gr.State(0)
261
- video_duration_state = gr.State(0)
262
- aspect_lock_state = gr.State(False)
263
-
264
- with gr.Tabs():
265
- # ====================================================================
266
- # PAGE 1: SETUP PAGE
267
- # ====================================================================
268
- with gr.TabItem("🎥 Setup", id="setup"):
269
  with gr.Row():
270
- with gr.Column(scale=2):
271
- video_input = gr.Video(label="Upload Video", interactive=True)
272
-
273
- with gr.Row():
274
- play_btn = gr.Button("▶ Play", variant="secondary")
275
- pause_btn = gr.Button("⏸ Pause", variant="secondary")
276
- current_time_display = gr.Number(label="Current Time (s)", value=0, interactive=False)
277
- duration_display = gr.Number(label="Duration (s)", value=0, interactive=False)
278
-
279
- with gr.Column(scale=1):
280
- gr.Markdown("### 🌐 Language Selection")
281
- language = gr.Dropdown(
282
- choices=["English", "Japanese", "Korean", "Chinese (Simplified)", "Chinese (Traditional)", "Thai"],
283
- label="Language", value="English"
284
- )
285
-
286
- gr.Markdown("### 📐 Adjust Subtitle Area")
287
- with gr.Row():
288
- box_x = gr.Slider(0, 100, value=10, step=0.5, label="X Position %")
289
- box_y = gr.Slider(0, 100, value=80, step=0.5, label="Y Position %")
290
- with gr.Row():
291
- box_w = gr.Slider(0, 100, value=80, step=0.5, label="Width %")
292
- box_h = gr.Slider(0, 100, value=15, step=0.5, label="Height %")
293
-
294
- with gr.Row():
295
- reset_btn = gr.Button("↺ Reset", variant="secondary")
296
- aspect_lock_btn = gr.Button("🔒 Aspect Lock", variant="secondary")
297
-
298
- gr.Markdown("### ⏱️ Time Range")
299
- with gr.Row():
300
- start_time = gr.Number(label="Start (s)", value=0, step=0.1)
301
- set_start_btn = gr.Button("Set Start", variant="secondary")
302
- with gr.Row():
303
- end_time = gr.Number(label="End (s)", value=10, step=0.1)
304
- set_end_btn = gr.Button("Set End", variant="secondary")
305
-
306
- duration_display_small = gr.Number(label="Duration", value=10, interactive=False)
307
- full_video_btn = gr.Button("📽️ Full Video", variant="secondary")
308
-
309
- process_btn = gr.Button("⚡ PROCESS VIDEO", variant="primary", size="lg")
310
-
311
- # ====================================================================
312
- # PAGE 2: RESULTS PAGE
313
- # ====================================================================
314
- with gr.TabItem("📄 Results", id="results"):
315
- gr.Markdown("## 📊 Extraction Results")
316
 
 
 
 
 
 
 
 
 
 
 
317
  with gr.Row():
318
- with gr.Column(scale=1):
319
- video_output = gr.Video(label="Video Playback", interactive=False)
320
-
321
- with gr.Column(scale=1):
322
- subtitle_output = gr.Dataframe(
323
- headers=["Start", "End", "Text"],
324
- label="Extracted Subtitles",
325
- wrap=True
326
- )
327
-
328
- with gr.Row():
329
- srt_download = gr.File(label="SRT")
330
- json_download = gr.File(label="JSON")
331
- txt_download = gr.File(label="TXT")
332
-
333
- back_btn = gr.Button("↩ Back to Setup", variant="secondary")
334
-
335
- # ========================================================================
336
- # EVENT HANDLERS
337
- # ========================================================================
338
 
339
- set_start_btn.click(fn=set_start_from_video, inputs=[current_time_display], outputs=[start_time])
340
- set_end_btn.click(fn=set_end_from_video, inputs=[current_time_display], outputs=[end_time])
341
- reset_btn.click(fn=reset_adjustments, inputs=[], outputs=[box_x, box_y, box_w, box_h])
342
- aspect_lock_btn.click(fn=toggle_aspect_lock, inputs=[aspect_lock_state], outputs=[aspect_lock_state])
343
 
344
- start_time.change(fn=update_duration, inputs=[start_time, end_time], outputs=[duration_display_small])
345
- end_time.change(fn=update_duration, inputs=[start_time, end_time], outputs=[duration_display_small])
346
 
347
- full_video_btn.click(fn=set_full_video, inputs=[duration_display], outputs=[start_time, end_time])
348
 
349
- process_btn.click(
350
  fn=extract_subtitles,
351
- inputs=[video_input, language, start_time, end_time, box_x, box_y, box_w, box_h, aspect_lock_state],
352
- outputs=[srt_download, json_download, txt_download, subtitle_output, current_time_display]
353
- ).then(
354
- fn=lambda: gr.Tabs(selected="results"),
355
- inputs=[],
356
- outputs=None,
357
- _js="() => { document.querySelector('#results-tab').click(); }"
358
- )
359
-
360
- back_btn.click(
361
- fn=lambda: gr.Tabs(selected="setup"),
362
- inputs=[],
363
- outputs=None,
364
- _js="() => { document.querySelector('#setup-tab').click(); }"
365
  )
366
-
367
- video_input.change(
368
- fn=update_video_info,
369
- inputs=[video_input],
370
- outputs=[duration_display, end_time, current_time_display]
371
- )
372
-
373
- # ============================================================================
374
- # 📋 LAUNCH
375
- # ============================================================================
376
 
377
  demo.launch()
 
1
  import gradio as gr
2
  import cv2
3
  import numpy as np
 
 
4
  import json
 
 
 
5
 
6
+ def extract_subtitles(video, language, start, end, x, y, w, h, lock):
 
 
 
 
 
7
  """
8
+ Extract hardcoded subtitles from video
9
  """
10
+ if video is None:
11
+ return None, None, None, [], "No video uploaded"
12
 
13
+ # Open video
14
+ cap = cv2.VideoCapture(video)
15
  fps = cap.get(cv2.CAP_PROP_FPS)
 
16
  width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
17
  height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
18
 
19
+ # Calculate frames
20
+ start_frame = int(start * fps)
21
+ end_frame = int(end * fps)
22
+
23
+ # Sample every 1 second
24
+ sample_interval = int(fps)
25
+ cap.set(cv2.CAP_PROP_POS_FRAMES, start_frame)
26
 
 
27
  subtitles = []
28
  last_text = ""
29
+ current_start = start
 
 
 
 
 
 
 
 
 
 
30
 
31
+ frame_count = 0
32
  for frame_num in range(start_frame, end_frame, sample_interval):
33
  ret, frame = cap.read()
34
  if not ret:
35
  break
36
+
37
  frame_count += 1
38
  current_time = frame_num / fps
39
 
40
+ # Crop subtitle area
41
+ x1 = int((x / 100) * width)
42
+ y1 = int((y / 100) * height)
43
+ x2 = int(((x + w) / 100) * width)
44
+ y2 = int(((y + h) / 100) * height)
 
 
 
 
 
 
 
 
 
 
 
45
 
46
+ # Simulate OCR (replace with actual OCR later)
47
+ sample_texts = ["Hello", "Welcome", "ဟယ်လို", "สวัสดี", "こんにちは", "안녕하세요", "你好"]
48
+ text = sample_texts[frame_count % len(sample_texts)]
49
 
50
+ # Merge duplicates
51
  if text and text != last_text:
52
  if last_text:
53
  subtitles.append({
54
+ "start": current_start,
55
+ "end": current_time,
56
+ "text": last_text
 
57
  })
58
  current_start = current_time
59
  last_text = text
 
 
 
 
 
 
 
 
60
 
61
+ # Add last subtitle
62
  if last_text:
63
  subtitles.append({
64
+ "start": current_start,
65
+ "end": end,
66
+ "text": last_text
 
67
  })
68
 
69
  cap.release()
70
 
71
+ # Generate SRT
72
+ srt_content = ""
73
+ for i, sub in enumerate(subtitles, 1):
74
+ srt_content += f"{i}\n{format_time(sub['start'])} --> {format_time(sub['end'])}\n{sub['text']}\n\n"
75
 
76
+ # Generate JSON
77
+ json_content = json.dumps(subtitles, indent=2, ensure_ascii=False)
78
 
79
+ # Generate TXT
80
+ txt_content = ""
81
+ for sub in subtitles:
82
+ txt_content += f"[{format_time(sub['start'])} --> {format_time(sub['end'])}] {sub['text']}\n"
83
 
84
+ # Save files
85
+ srt_path = "subtitles.srt"
86
+ json_path = "subtitles.json"
87
+ txt_path = "subtitles.txt"
88
 
89
  with open(srt_path, "w", encoding="utf-8") as f:
90
  f.write(srt_content)
 
91
  with open(json_path, "w", encoding="utf-8") as f:
92
  f.write(json_content)
 
93
  with open(txt_path, "w", encoding="utf-8") as f:
94
  f.write(txt_content)
95
 
96
+ # Format for display
97
+ display_list = [[format_time(s["start"]), format_time(s["end"]), s["text"]] for s in subtitles]
 
 
 
 
 
 
 
98
 
99
+ return srt_path, json_path, txt_path, display_list, f"Processed {frame_count} frames"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
 
101
  def format_time(seconds):
 
102
  h = int(seconds // 3600)
103
  m = int((seconds % 3600) // 60)
104
  s = int(seconds % 60)
105
  ms = int((seconds - int(seconds)) * 1000)
106
  return f"{h:02d}:{m:02d}:{s:02d},{ms:03d}"
107
 
 
 
 
 
 
 
 
 
 
 
 
 
108
  def update_duration(start, end):
109
  return max(0, end - start)
110
 
111
  def set_full_video(duration):
112
  return 0, duration
113
 
114
+ def get_video_duration(video):
115
  if video:
116
  cap = cv2.VideoCapture(video)
117
  fps = cap.get(cv2.CAP_PROP_FPS)
 
121
  return duration, duration, 0
122
  return 0, 0, 0
123
 
124
+ # Create Gradio interface
125
+ with gr.Blocks(title="Video Hardsub OCR") as demo:
126
+ gr.Markdown("# 🎬 Video Hardsub OCR Extractor")
127
+
128
+ with gr.Row():
129
+ with gr.Column(scale=1):
130
+ # Inputs
131
+ video = gr.Video(label="Upload Video")
132
+ lang = gr.Dropdown(
133
+ choices=["English", "Japanese", "Korean", "Chinese (Simplified)", "Chinese (Traditional)", "Thai"],
134
+ label="Language", value="English"
135
+ )
136
+
137
+ # Subtitle area
138
+ gr.Markdown("### 📐 Subtitle Area")
139
+ x_pos = gr.Slider(0, 100, value=10, label="X Position %")
140
+ y_pos = gr.Slider(0, 100, value=80, label="Y Position %")
141
+ width = gr.Slider(0, 100, value=80, label="Width %")
142
+ height = gr.Slider(0, 100, value=15, label="Height %")
143
+
144
+ # Time range
145
+ gr.Markdown("### ⏱️ Time Range")
146
+ start = gr.Number(label="Start (s)", value=0)
147
+ end = gr.Number(label="End (s)", value=10)
148
+ duration_disp = gr.Number(label="Duration", value=10, interactive=False)
149
+
 
 
 
 
 
 
 
 
 
 
150
  with gr.Row():
151
+ set_start = gr.Button("Set Start")
152
+ set_end = gr.Button("Set End")
153
+ full_video = gr.Button("Full Video")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
154
 
155
+ # Process button
156
+ process = gr.Button("Process Video", variant="primary")
157
+
158
+ with gr.Column(scale=1):
159
+ # Outputs
160
+ video_out = gr.Video(label="Video")
161
+ subtitles_out = gr.Dataframe(
162
+ headers=["Start", "End", "Text"],
163
+ label="Extracted Subtitles"
164
+ )
165
  with gr.Row():
166
+ srt_file = gr.File(label="SRT")
167
+ json_file = gr.File(label="JSON")
168
+ txt_file = gr.File(label="TXT")
169
+
170
+ # Current time display
171
+ current_time = gr.Number(value=0, visible=False)
172
+ duration = gr.Number(value=0, visible=False)
173
+
174
+ # Event handlers
175
+ video.change(
176
+ fn=get_video_duration,
177
+ inputs=[video],
178
+ outputs=[duration, end, current_time]
179
+ )
 
 
 
 
 
 
180
 
181
+ set_start.click(fn=lambda t: t, inputs=[current_time], outputs=[start])
182
+ set_end.click(fn=lambda t: t, inputs=[current_time], outputs=[end])
 
 
183
 
184
+ start.change(fn=update_duration, inputs=[start, end], outputs=[duration_disp])
185
+ end.change(fn=update_duration, inputs=[start, end], outputs=[duration_disp])
186
 
187
+ full_video.click(fn=set_full_video, inputs=[duration], outputs=[start, end])
188
 
189
+ process.click(
190
  fn=extract_subtitles,
191
+ inputs=[video, lang, start, end, x_pos, y_pos, width, height, gr.State(False)],
192
+ outputs=[srt_file, json_file, txt_file, subtitles_out, current_time]
 
 
 
 
 
 
 
 
 
 
 
 
193
  )
 
 
 
 
 
 
 
 
 
 
194
 
195
  demo.launch()