basyx commited on
Commit
b935de9
·
verified ·
1 Parent(s): 9510d07

Update utils/subtitle_engine.py

Browse files
Files changed (1) hide show
  1. utils/subtitle_engine.py +43 -9
utils/subtitle_engine.py CHANGED
@@ -1,31 +1,65 @@
 
 
 
1
  class SubtitleEngine:
2
  def __init__(self, words_per_frame=4):
 
 
 
 
3
  self.words_per_frame = words_per_frame
4
 
5
  def create_highlight_chunks(self, segments):
6
  """
7
- Creates frames where 3-5 words are visible, but the current
8
- spoken word is highlighted.
9
  """
10
  highlight_frames = []
 
11
  for segment in segments:
12
  if not hasattr(segment, 'words') or not segment.words:
13
  continue
14
 
15
  words = segment.words
16
- # Break words into frames of size N
 
17
  for i in range(0, len(words), self.words_per_frame):
18
  frame_words = words[i : i + self.words_per_frame]
19
 
20
- # For each word in the frame, create a unique timestamp entry
21
- # where that specific word is the "active" one
22
  for active_index, active_word in enumerate(frame_words):
 
 
 
 
 
 
 
 
 
 
 
23
  highlight_frames.append({
24
- "full_frame_text": [w.word.strip().upper() for w in frame_words],
25
  "active_word_index": active_index,
26
- "start": active_word.start,
27
- "end": active_word.end
28
  })
 
 
29
  return highlight_frames
30
 
31
- sub_engine = SubtitleEngine()
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import re
2
+ from .logger import logger
3
+
4
  class SubtitleEngine:
5
  def __init__(self, words_per_frame=4):
6
+ """
7
+ words_per_frame: Number of words visible on screen at once.
8
+ TikTok style usually favors 3-5 words for readability.
9
+ """
10
  self.words_per_frame = words_per_frame
11
 
12
  def create_highlight_chunks(self, segments):
13
  """
14
+ Processes faster-whisper segments into frames optimized for
15
+ Pango highlighting and rhythmic 'pop' effects.
16
  """
17
  highlight_frames = []
18
+
19
  for segment in segments:
20
  if not hasattr(segment, 'words') or not segment.words:
21
  continue
22
 
23
  words = segment.words
24
+
25
+ # Group words into frames of size N (default 4)
26
  for i in range(0, len(words), self.words_per_frame):
27
  frame_words = words[i : i + self.words_per_frame]
28
 
29
+ # Each word in this frame needs its own 'frame' entry in the
30
+ # renderer so that the highlight moves as the word is spoken.
31
  for active_index, active_word in enumerate(frame_words):
32
+
33
+ # Ensure start/end times are logical
34
+ start = active_word.start
35
+ end = active_word.end
36
+
37
+ # If it's the last word in the frame, we can hold it
38
+ # slightly longer or until the next frame starts
39
+ if active_index == len(frame_words) - 1:
40
+ # Small buffer to prevent flicker between frames
41
+ end += 0.1
42
+
43
  highlight_frames.append({
44
+ "full_frame_text": [self._clean_text(w.word) for w in frame_words],
45
  "active_word_index": active_index,
46
+ "start": start,
47
+ "end": end
48
  })
49
+
50
+ logger.info(f"Generated {len(highlight_frames)} highlight frames for rendering.")
51
  return highlight_frames
52
 
53
+ def _clean_text(self, text):
54
+ """
55
+ Standardizes text for TikTok style:
56
+ - All caps
57
+ - No leading/trailing whitespace
58
+ - Strips special characters that might break Pango markup
59
+ """
60
+ clean = text.strip().upper()
61
+ # Escaping characters that break XML/Pango if necessary
62
+ clean = clean.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
63
+ return clean
64
+
65
+ sub_engine = SubtitleEngine(words_per_frame=4)