Spaces:
Running
on
Zero
Running
on
Zero
File size: 4,671 Bytes
a7334d4 a1ddd2f a7334d4 a1ddd2f a7334d4 a1ddd2f a7334d4 a1ddd2f 8e872fa a1ddd2f bd37c28 a7334d4 a1ddd2f a7334d4 a1ddd2f a7334d4 a1ddd2f a7334d4 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
def regroup_words(
words: list[dict],
max_len: float = 15.0,
gap: float = 0.50,
) -> list[dict]:
"""
Returns a list of segments with keys:
'start', 'end', 'text', 'words'
"""
if not words:
return []
segs, seg_words = [], []
seg_start = words[0]["start"]
last_end = seg_start
for w in words:
over_max = (w["end"] - seg_start) > max_len
long_gap = (w["start"] - last_end) > gap
if (seg_words and (over_max or long_gap)):
segs.append({
"start": seg_start,
"end": last_end,
"segment": " ".join(x["word"] for x in seg_words),
})
seg_words = []
seg_start = w["start"]
seg_words.append(w)
last_end = w["end"]
# flush final segment
segs.append({
"start": seg_start,
"end": last_end,
"segment": " ".join(x["word"] for x in seg_words),
})
return segs
def text_to_words(text: str) -> list[dict]:
"""
Convert text format like "word[start:end] word[start:end]..." to word list.
Args:
text: String in format "It's[4.96:5.52] a[5.52:5.84] long[5.84:6.16]..."
Returns:
List of word dictionaries with keys: 'word', 'start', 'end'
"""
import re
if not text.strip():
return []
# Pattern to match word[start:end] format
pattern = r'(\S+?)\[([^:]+):([^\]]+)\]'
matches = re.findall(pattern, text)
words = []
for word, start_str, end_str in matches:
try:
start = float(start_str) if start_str != 'xxx' else 0.0
end = float(end_str) if end_str != 'xxx' else 0.0
words.append({
'word': word,
'start': start,
'end': end
})
except ValueError:
# Skip invalid entries
continue
return words
def words_to_text(words: list[dict]) -> str:
"""
Convert word list to text format "word[start:end] word[start:end]...".
Args:
words: List of word dictionaries with keys: 'word', 'start', 'end'
Returns:
String in format "It's[4.96:5.52] a[5.52:5.84] long[5.84:6.16]..."
"""
if not words:
return ""
text_parts = []
for word in words:
word_text = word.get('word', '')
start = word.get('start', 0.0)
end = word.get('end', 0.0)
# Format timestamps to max 2 decimal places
start_str = f"{start:.2f}".rstrip('0').rstrip('.')
end_str = f"{end:.2f}".rstrip('0').rstrip('.')
text_parts.append(f"{word_text}[{start_str}:{end_str}]")
return " ".join(text_parts)
def json_to_text(json_data: dict) -> str:
"""
Convert JSON lyrics data to text format for display.
Only uses the 'word' layer from the JSON structure.
Groups words into sentences/lines for better readability.
Args:
json_data: Dictionary with 'word' key containing list of word objects
Returns:
String with words grouped into lines: "word[start:end] word[start:end]...\nword[start:end]..."
"""
if not isinstance(json_data, dict) or 'word' not in json_data:
return ""
words = json_data['word']
# Group words into segments using the existing regroup_words function
segments = regroup_words(words, max_len=5, gap=0.50)
# Convert each segment to text format
segment_lines = []
for seg in segments:
# Extract words for this segment based on time range
seg_words = []
for word in words:
if seg['start'] <= word['start'] < seg['end'] or (
word['start'] <= seg['start'] < word['end']
):
seg_words.append(word)
if seg_words:
segment_text = words_to_text(seg_words)
segment_lines.append(segment_text)
return '\n\n'.join(segment_lines)
def text_to_json(text: str) -> dict:
"""
Convert text format to JSON structure expected by the model.
Creates the 'word' layer that the model needs.
Handles multi-line input by joining lines.
Args:
text: String in format "word[start:end] word[start:end]..." (can be multi-line)
Returns:
Dictionary with 'word' key containing list of word objects
"""
# Join multiple lines into single line for parsing
single_line_text = ' '.join(line.strip() for line in text.split('\n') if line.strip())
words = text_to_words(single_line_text)
return {"word": words}
|