Update app.py
Browse files
app.py
CHANGED
|
@@ -35,6 +35,7 @@ os.makedirs(AUDIO_DIR, exist_ok=True)
|
|
| 35 |
API_KEY = "rkmentormindzofficaltokenkey12345"
|
| 36 |
|
| 37 |
|
|
|
|
| 38 |
import os
|
| 39 |
import re
|
| 40 |
import html
|
|
@@ -55,7 +56,9 @@ from mutagen.mp3 import MP3
|
|
| 55 |
# Voice configuration
|
| 56 |
VOICE_EN = "en-IN-NeerjaNeural"
|
| 57 |
|
| 58 |
-
|
|
|
|
|
|
|
| 59 |
|
| 60 |
# Pre-compiled regex patterns for speed
|
| 61 |
URL_PATTERN = re.compile(r'https?://[^\s<>"\']+|www\.[^\s<>"\']+')
|
|
@@ -63,8 +66,10 @@ TAG_PATTERN = re.compile(r'<[^>]*>|[<>]')
|
|
| 63 |
BRACKET_PATTERN = re.compile(r'[\{\}\[\]]')
|
| 64 |
SPECIAL_CHAR_PATTERN = re.compile(r'[#@$%^&*_+=|\\`~]')
|
| 65 |
WHITESPACE_PATTERN = re.compile(r'\s+')
|
| 66 |
-
|
| 67 |
-
|
|
|
|
|
|
|
| 68 |
|
| 69 |
|
| 70 |
@lru_cache(maxsize=1024)
|
|
@@ -129,12 +134,13 @@ async def generate_safe_audio(text, voice, semaphore):
|
|
| 129 |
|
| 130 |
|
| 131 |
@lru_cache(maxsize=256)
|
| 132 |
-
def smart_text_chunking(text, max_chars=
|
| 133 |
-
"""Cached text chunking with larger
|
| 134 |
text = clean_text_for_tts(text)
|
| 135 |
if not text:
|
| 136 |
return tuple()
|
| 137 |
|
|
|
|
| 138 |
sentences = SENTENCE_PATTERN.split(text)
|
| 139 |
chunks = []
|
| 140 |
|
|
@@ -143,30 +149,46 @@ def smart_text_chunking(text, max_chars=200):
|
|
| 143 |
if not sentence:
|
| 144 |
continue
|
| 145 |
|
|
|
|
| 146 |
if len(sentence) <= max_chars:
|
| 147 |
chunks.append(sentence)
|
| 148 |
else:
|
|
|
|
| 149 |
sub_parts = SUB_PATTERN.split(sentence)
|
|
|
|
|
|
|
| 150 |
for part in sub_parts:
|
| 151 |
part = part.strip()
|
| 152 |
if not part:
|
| 153 |
continue
|
| 154 |
|
| 155 |
-
|
| 156 |
-
|
|
|
|
|
|
|
| 157 |
else:
|
| 158 |
-
words = part.split()
|
| 159 |
-
current_chunk = ""
|
| 160 |
-
for word in words:
|
| 161 |
-
test_chunk = f"{current_chunk} {word}" if current_chunk else word
|
| 162 |
-
if len(test_chunk) <= max_chars:
|
| 163 |
-
current_chunk = test_chunk
|
| 164 |
-
else:
|
| 165 |
-
if current_chunk:
|
| 166 |
-
chunks.append(current_chunk.strip())
|
| 167 |
-
current_chunk = word
|
| 168 |
if current_chunk:
|
| 169 |
chunks.append(current_chunk.strip())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 170 |
|
| 171 |
return tuple(chunk for chunk in chunks if chunk.strip())
|
| 172 |
|
|
@@ -242,7 +264,7 @@ async def bilingual_tts_optimized(text, output_file="audio0.mp3", VOICE_TA=None,
|
|
| 242 |
|
| 243 |
print("Merging audio segments...")
|
| 244 |
merged_audio = audio_segments[0]
|
| 245 |
-
pause = AudioSegment.silent(duration=
|
| 246 |
|
| 247 |
for segment in audio_segments[1:]:
|
| 248 |
merged_audio += pause + segment
|
|
@@ -346,6 +368,7 @@ def audio_func(id, lines, lang):
|
|
| 346 |
|
| 347 |
|
| 348 |
|
|
|
|
| 349 |
def create_manim_script(problem_data, script_path, audio_path, scale=1):
|
| 350 |
"""Generate Manim script from problem data with robust wrapping."""
|
| 351 |
|
|
|
|
| 35 |
API_KEY = "rkmentormindzofficaltokenkey12345"
|
| 36 |
|
| 37 |
|
| 38 |
+
|
| 39 |
import os
|
| 40 |
import re
|
| 41 |
import html
|
|
|
|
| 56 |
# Voice configuration
|
| 57 |
VOICE_EN = "en-IN-NeerjaNeural"
|
| 58 |
|
| 59 |
+
# Directory paths - ensure they exist
|
| 60 |
+
AUDIO_DIR = os.path.join(os.getcwd(), "audio")
|
| 61 |
+
os.makedirs(AUDIO_DIR, exist_ok=True)
|
| 62 |
|
| 63 |
# Pre-compiled regex patterns for speed
|
| 64 |
URL_PATTERN = re.compile(r'https?://[^\s<>"\']+|www\.[^\s<>"\']+')
|
|
|
|
| 66 |
BRACKET_PATTERN = re.compile(r'[\{\}\[\]]')
|
| 67 |
SPECIAL_CHAR_PATTERN = re.compile(r'[#@$%^&*_+=|\\`~]')
|
| 68 |
WHITESPACE_PATTERN = re.compile(r'\s+')
|
| 69 |
+
# More conservative sentence splitting - only on major punctuation with space
|
| 70 |
+
SENTENCE_PATTERN = re.compile(r'(?<=[.!?।॥])\s+')
|
| 71 |
+
# More conservative sub-splitting - avoid splitting on hyphens and preserve word boundaries
|
| 72 |
+
SUB_PATTERN = re.compile(r'(?<=[,;])\s+')
|
| 73 |
|
| 74 |
|
| 75 |
@lru_cache(maxsize=1024)
|
|
|
|
| 134 |
|
| 135 |
|
| 136 |
@lru_cache(maxsize=256)
|
| 137 |
+
def smart_text_chunking(text, max_chars=300):
|
| 138 |
+
"""Cached text chunking with larger chunks and better preservation of word order."""
|
| 139 |
text = clean_text_for_tts(text)
|
| 140 |
if not text:
|
| 141 |
return tuple()
|
| 142 |
|
| 143 |
+
# First try to split on major sentence boundaries
|
| 144 |
sentences = SENTENCE_PATTERN.split(text)
|
| 145 |
chunks = []
|
| 146 |
|
|
|
|
| 149 |
if not sentence:
|
| 150 |
continue
|
| 151 |
|
| 152 |
+
# If sentence fits, keep it whole
|
| 153 |
if len(sentence) <= max_chars:
|
| 154 |
chunks.append(sentence)
|
| 155 |
else:
|
| 156 |
+
# Try splitting on commas/semicolons but preserve larger context
|
| 157 |
sub_parts = SUB_PATTERN.split(sentence)
|
| 158 |
+
current_chunk = ""
|
| 159 |
+
|
| 160 |
for part in sub_parts:
|
| 161 |
part = part.strip()
|
| 162 |
if not part:
|
| 163 |
continue
|
| 164 |
|
| 165 |
+
test_chunk = f"{current_chunk}, {part}" if current_chunk else part
|
| 166 |
+
|
| 167 |
+
if len(test_chunk) <= max_chars:
|
| 168 |
+
current_chunk = test_chunk
|
| 169 |
else:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 170 |
if current_chunk:
|
| 171 |
chunks.append(current_chunk.strip())
|
| 172 |
+
|
| 173 |
+
# If single part is too long, split by words carefully
|
| 174 |
+
if len(part) > max_chars:
|
| 175 |
+
words = part.split()
|
| 176 |
+
word_chunk = ""
|
| 177 |
+
for word in words:
|
| 178 |
+
test_word_chunk = f"{word_chunk} {word}" if word_chunk else word
|
| 179 |
+
if len(test_word_chunk) <= max_chars:
|
| 180 |
+
word_chunk = test_word_chunk
|
| 181 |
+
else:
|
| 182 |
+
if word_chunk:
|
| 183 |
+
chunks.append(word_chunk.strip())
|
| 184 |
+
word_chunk = word
|
| 185 |
+
if word_chunk:
|
| 186 |
+
current_chunk = word_chunk
|
| 187 |
+
else:
|
| 188 |
+
current_chunk = part
|
| 189 |
+
|
| 190 |
+
if current_chunk:
|
| 191 |
+
chunks.append(current_chunk.strip())
|
| 192 |
|
| 193 |
return tuple(chunk for chunk in chunks if chunk.strip())
|
| 194 |
|
|
|
|
| 264 |
|
| 265 |
print("Merging audio segments...")
|
| 266 |
merged_audio = audio_segments[0]
|
| 267 |
+
pause = AudioSegment.silent(duration=150)
|
| 268 |
|
| 269 |
for segment in audio_segments[1:]:
|
| 270 |
merged_audio += pause + segment
|
|
|
|
| 368 |
|
| 369 |
|
| 370 |
|
| 371 |
+
|
| 372 |
def create_manim_script(problem_data, script_path, audio_path, scale=1):
|
| 373 |
"""Generate Manim script from problem data with robust wrapping."""
|
| 374 |
|